I want to build a method that returns a child
value in FireBase
. I tried to do something like this:
public String getMessage(){
Firebase usually takes about 1-2 seconds to load the data.
So keeping that in mind you can add a new thread using Handler, to make the system wait for say, 2 Seconds and then use the value retrieved from the Database.
Till then you can display a Loading Dialog box to the user which can be closed once the data is retrieved.
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
Don't use Firebase as functions that return values - it goes against it's asynchronous nature.
Plan code structure that allows Firebase to perform it's task and then within the closure (block) go to the next step.
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.
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 -
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!
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
You can use CountDownLatch. This is how you can use it.
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];
}
You can follow this link 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
Create a new class Ex. Firebasedata.java and extent it with Application and add put this code in the OnCreate sections
public class Firebasedata extends Application {
@Override
public void onCreate() {
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
super.onCreate();
}
}
declare the java class in the manifests
<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