我想构建一个在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;
}
问题是该方法返回null
,这可能是因为该方法不会等到侦听器完成并返回null
,因为它的默认值为message
。
如何使此方法等到侦听器出现然后返回值。
答案 0 :(得分:9)
制作界面
public interface OnGetDataListener {
//this is for callbacks
void onSuccess(DataSnapshot dataSnapshot);
void onStart();
void onFailure();
}
声明以下函数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();
}
});
}
调用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()可以在你的getMessage()方法中调用,甚至可以在onCreate()里面调用
答案 1 :(得分:4)
您可以使用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];
}
答案 2 :(得分:3)
不要将Firebase用作返回值的函数 - 它违背了它的异步性质。
规划代码结构,允许Firebase执行它的任务,然后在闭包(块)内转到下一步。
在您的代码中,例如,将函数更改为不返回任何内容并在onDataChange中,因为最后一行调用下一个更新UI的函数。
答案 3 :(得分:1)
正如@ CMikeB1在处理servlet和服务其余部分(我们使用同步调用来执行操作)时对java世界中的另一个响应进行评论时,在sdk firebase admin中同时使用这两个选项将很有用,以便开发人员可以选择根据他的情况使用。
我的实现是从等待使用ApiFuture读取同步数据开始的,ApiFuture是firebase管理员的sdk采用的当前接口。这里是a link!
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;
}
}
答案 4 :(得分:1)
您可以点击此链接https://youtu.be/LVaIArVY52U
Firebase数据库在检索数据时非常慢,因此可以使应用程序等待过程完成,您可以按照以下步骤
创建一个新的类Ex。 Firebasedata.java并使用Application对其进行扩展,并将此代码添加到OnCreate部分中
public class Firebasedata extends Application {
@Override
public void onCreate() {
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
super.onCreate();
}
}
在清单中声明Java类
<application
android:name=".Firebasedata" <------
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
...
...
</application>
然后返回您要获取数据的类,并使用此代码创建一个对话框
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();
您可以查看上面的链接,以获得更好的主意
答案 5 :(得分:1)
@Joseph 的最高答案几乎是正确的!他的回答绝对是最简单、最容易理解和实施的,所以我要借助他的回答并纠正一个致命的缺陷。
第 1 步:就像他上面所说的,使用简单的回调接口就可以了,就像这样:
public interface OnGetDataListener {
//this is for callbacks
void onSuccess(String dataSnapshotValue);
}
第 2 步:创建一个方法,该方法接受接口的实现作为参数,并查询 Firebase 数据库。 这是原始回答者犯错的地方...而不是传递 DataSnapshot到回调,你必须传递快照的值。
public void readData(Firebase ref, final OnGetDataListener listener) {
ref.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
// This is how you use the value once it is loaded! Make sure to pass the
// value of the DataSnapshot object, not the object itself (this was the
// original answerer's mistake!
listener.onSuccess(dataSnapshot.getValue());
}
@Override
public void onCancelled(FirebaseError firebaseError) {}
});
}
第3步:调用上面的函数,并传递一个回调接口的实现,在数据加载后处理数据。
readData(root.child("MessagesOnLaunch").child("Message"), new OnGetDataListener() {
@Override
public void onSuccess(String dataSnapshotValue) {
// This is where you can handle the snapshot's value! (log it, add it
// to a list, etc.)
}
});
答案 6 :(得分:0)
我将在此处保留此内容,以帮助遇到与我相同的问题的任何人。 @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;
}
请注意,该函数只能返回消息类型Integer。我无法让它适用于String,因为String没有原子类型。希望这会有所帮助!
答案 7 :(得分:0)
很抱歉,这次聚会来得有点晚,但是您可以设置观察者/视图模型,而不是让Firebase返回一个值,那么当您运行异步firebase函数时,将以此调用onData方法,您将更新视图对数据建模,然后触发其onDataChanged方法,然后您可以从中更新布局
答案 8 :(得分:0)
Firebase通常需要大约1-2秒来加载数据。
因此请记住,您可以使用Handler添加新线程,使系统等待2秒,然后使用从数据库中检索到的值。
然后,您可以向用户显示“正在加载”对话框,一旦检索到数据,即可关闭该对话框。
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
{
loadingDialog.dismiss();//dismiss the dialog box once data is retreived
Toast.makeText(Act_NewHome.this, "Not enough players online right now!", Toast.LENGTH_SHORT).show();
tvUserName.setText(u_name);
}
}
}, 2000);// 2000 milliseconds = 2seconds
答案 9 :(得分:0)
将此代码添加到onDataChange()
方法中
do{
message = (String) dataSnapshot.getValue();
if(message.equals(null))
break;
}while (!message.equals(null));
答案 10 :(得分:0)
经过长时间的研究,我找不到它,所以我按自己的方式做了。可以这样做。但是这段代码在主线程上并不安全,因为它等待直到数据恢复。所以如果你在 Main Thread 上使用它,它会有很大的负载。我添加了 WorkerThread Annotation 来告诉它不应该在 UIThread 中使用,另一个 new Thread 是安全的。我测试过,它在 new Thread 上工作,但不在 Main Thread
上课堂
public static class DBUtils{
private boolean fetched;
private DataSnapshot result;
private DatabaseReference dbr;
private DatabaseException err;
private DBUtils(DatabaseReference dbr){
this.dbr=dbr;
}
private DataSnapshot fetch(boolean error){
result=null;
if(dbr!=null){
fetched=false;
dbr.addListenerForSingleValueEvent(new ValueEventListener(){
@Override
public void onDataChange(DataSnapshot data)
{
result=data;
done();
}
@Override
public void onCancelled(DatabaseError e)
{
err=e.toException();
done();
}
private void done()
{
fetched=true;
//dbr.removeEventListener(this);
}
});
}else{
fetched=true;
}
while(!fetched){
// wait
}
if(error&&err!=null){
throw err;
}
return result;
}
@WorkerThread
public static @Nullable DataSnapshot getRealtimeValue(@NonNull DatabaseReference ref)
{
return getRealtimeValue(ref,false);
}
@WorkerThread
public static @Nullable DataSnapshot getRealtimeValue(@NonNull DatabaseReference ref, boolean throwError) throws DatabaseException
{
return new DBUtils(ref).fetch(throwError);
}
}
使用
...
DatabaseReference ref = ...: // Your ref goes here
boolean throwError = false; // if true, the code will throw the error occurred during data fetching, else if false, it will just skip it and return null
DataSnapshot result = DBUtils.getRealtimeValue(ref, throwError);
...
不要忘记给我投票,因为我几乎不需要投票来帮助他人。如果这是您想要的,也将其标记为已解决
——DiLDoST