Java 等到 firebase 检索数据
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/30659569/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
wait until firebase retrieves data
提问by ben
I want to build a method that returns a child
value in FireBase
. I tried to do something like this:
我想构建一个返回child
值的方法FireBase
。我试图做这样的事情:
public String getMessage(){
root.child("MessagesOnLaunch").child("Message").addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
message = (String) dataSnapshot.getValue();
Log.i("4r398", "work");
}
@Override
public void onCancelled(FirebaseError firebaseError) {
Log.e("error", firebaseError.getMessage());
}
});
return message;
}
The problem is that the method returns null
that is probably because the method doesn't wait until the listener finishes and return null
because its the default value of message
.
How can I make this method wait until the listener occurs and then return the value.
问题是该方法返回null
这可能是因为该方法不会等到侦听器完成并返回,null
因为它的默认值是message
. 我怎样才能让这个方法等到监听器发生然后返回值。
回答by Vladyslav Ulianytskyi
Don't use Firebase as functions that return values - it goes against it's asynchronous nature.
不要将 Firebase 用作返回值的函数 - 这违背了它的异步性质。
Plan code structure that allows Firebase to perform it's task and then within the closure (block) go to the next step.
规划允许 Firebase 执行其任务的代码结构,然后在闭包(块)内进入下一步。
In your code, for example, change the function to not return anything and within the onDataChange, as the last line call the next function to update your UI.
例如,在您的代码中,将函数更改为不返回任何内容并在 onDataChange 中,因为最后一行调用 next 函数来更新您的 UI。
回答by Joseph Varghese
Make an interface
做一个界面
public interface OnGetDataListener {
//this is for callbacks
void onSuccess(DataSnapshot dataSnapshot);
void onStart();
void onFailure();
}
Declare the following function readData()
声明以下函数 readData()
public void readData(Firebase ref, final OnGetDataListener listener) {
listener.onStart();
ref.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
listener.onSuccess(dataSnapshot);
}
@Override
public void onCancelled(FirebaseError firebaseError) {
listener.onFailure();
}
});
}
Call the readData() function as follows
调用 readData() 函数如下
readData(root.child("MessagesOnLaunch").child("Message"), new OnGetDataListener() {
@Override
public void onSuccess(DataSnapshot dataSnapshot) {
//got data from database....now you can use the retrieved data
}
@Override
public void onStart() {
//when starting
Log.d("ONSTART", "Started");
}
@Override
public void onFailure() {
Log.d("onFailure", "Failed");
}
});
readData() can be called inside your getMessage() method or even inside onCreate()
readData() 可以在你的 getMessage() 方法中调用,甚至在 onCreate() 中调用
回答by Tirupati Singh
You can use CountDownLatch. This is how you can use it.
您可以使用 CountDownLatch。这就是您可以使用它的方式。
public String getMessage(){
CountDownLatch done = new CountDownLatch(1);
final String message[] = {null};
root.child("MessagesOnLaunch").child("Message").addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
message[0] = (String) dataSnapshot.getValue();
System.out.println("worked");
done.countDown();
}
@Override
public void onCancelled(FirebaseError firebaseError) {
System.out.println("failed"+firebaseError.getMessage());
}
});
try {
done.await(); //it will wait till the response is received from firebase.
} catch(InterruptedException e) {
e.printStackTrace();
}
return message[0];
}
回答by Zod
I'll leave this here to help anyone who faces the same problem as me. @Tirupati Singh code looks nice but I wrote my answer below his why it didn't work for me. Using Atomic type worked -
我将把它留在这里以帮助与我面临同样问题的任何人。@Tirupati Singh 代码看起来不错,但我在他的下面写了我的答案,为什么它对我不起作用。使用原子类型工作 -
public AtomicInteger getMessage(){
final AtomicBoolean done = new AtomicBoolean(false);
final AtomicInteger message1 = new AtomicInteger(0);
//assuming you have already called firebase initialization code for admin sdk, android etc
DatabaseReference root = FirebaseDatabase.getInstance().getReference("server");
root.child("MessagesOnLaunch").child("Message").addListenerForSingleValueEvent(new ValueEventListener() {
public void onDataChange(DataSnapshot dataSnapshot) {
message1.set((Integer) dataSnapshot.getValue());
done.set(true);
}
public void onCancelled(DatabaseError error) {
// TODO Auto-generated method stub
}
});
while (!done.get());
return message1;
}
Note the function can only return message type Integer. I couldn't get it to work for String as no Atomic type for String. Hope this helps!
请注意,该函数只能返回消息类型 Integer。我无法让它为 String 工作,因为 String 没有原子类型。希望这可以帮助!
回答by Pedro Bacchini
As @CMikeB1 commented on another response in the java world when we are dealing with servlets and services rest we use sync calls to perform operations, it would be useful to have both options in sdk firebase admin so that the developer could choose which one to use depending on his case use.
正如@CMikeB1 在我们处理 servlet 和服务休息时对 Java 世界中的另一个响应所评论的那样,我们使用同步调用来执行操作,在 sdk firebase admin 中同时拥有这两个选项会很有用,以便开发人员可以选择使用哪一个根据他的情况使用。
I made my implementation from waiting to read the sync data using ApiFuture which is the current interface adopted by the sdk of the firebase admin. here's a link!
我使用 ApiFuture 等待读取同步数据来实现我的实现,ApiFuture 是 firebase 管理员的 sdk 采用的当前接口。这是一个链接!
public DataSnapshot getMessage() {
final SettableApiFuture<DataSnapshot> future = SettableApiFuture.create();
databaseReference.child("MessagesOnLaunch").child("Message").addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
future.set(dataSnapshot);
}
@Override
public void onCancelled(DatabaseError databaseError) {
future.setException(databaseError.toException());
}
});
try {
return future.get();
} catch(InterruptedException | ExecutionException e) {
e.printStackTrace();
return null;
}
}
回答by martinseal1987
Sorry to be a little late to this party but rather than have firebase return a value you could set up an observer / view model, then when you run your async firebase function the onData method is called from this you would update your view models data which then triggers its onDataChanged method which you can then update your layout from
很抱歉参加这个派对有点晚了,但不是让 firebase 返回一个值,你可以设置一个观察者/视图模型,然后当你运行你的异步 firebase 函数时,onData 方法被调用,你会更新你的视图模型数据然后触发它的 onDataChanged 方法,然后您可以从中更新您的布局
回答by Gnana Sreekar
You can follow this link https://youtu.be/LVaIArVY52U
您可以点击此链接https://youtu.be/LVaIArVY52U
Firebase database is quite slow when retrieving the data so to make the application wait for the process to complete you can follow this
Firebase 数据库在检索数据时速度很慢,因此要使应用程序等待该过程完成,您可以按照此操作
Create a new class Ex. Firebasedata.java and extent it with Application and add put this code in the OnCreate sections
创建一个新类 Ex。Firebasedata.java 并使用 Application 扩展它并添加将此代码放在 OnCreate 部分中
public class Firebasedata extends Application {
@Override
public void onCreate() {
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
super.onCreate();
}
}
declare the java class in the manifests
在清单中声明 java 类
<application
android:name=".Firebasedata" <------
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
...
...
</application>
Then go back to the class where you want to get the data and create a dialog with this code
然后回到你想获取数据的类,用这段代码创建一个对话框
ProgressDialog TempDialog;
CountDownTimer mCountDownTimer;
int i=0;
TempDialog = new ProgressDialog(MainActivity.this);
TempDialog.setMessage("Please wait...");
TempDialog.setCancelable(false);
TempDialog.setProgress(i);
TempDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
TempDialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.GRAY));
TempDialog.show();
mCountDownTimer = new CountDownTimer(2000, 1000)
{
public void onTick(long millisUntilFinished)
{
TempDialog.setMessage("Please wait..");
}
public void onFinish()
{
TempDialog.dismiss();
//Your action like intents are placed here
}
}.start();
You can look into the link above and get a better idea
您可以查看上面的链接并获得更好的主意