Update UI AFTER getting data from Firebase Database
Update UI AFTER getting data from Firebase Database
I've got a Firebase Database with User data. And I have a User class with this method:
private void getFromFirebase()
final FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference reference = database.getReference( FirebaseReferences.USERS ).child( userId );
reference.addValueEventListener( new ValueEventListener()
@Override
public void onDataChange( @NonNull DataSnapshot dataSnapshot )
display_name = dataSnapshot.child( "username" ).getValue( String.class );
photo = dataSnapshot.child( "profile_image" ).getValue( String.class );
@Override
public void onCancelled( @NonNull DatabaseError databaseError )
);
In the MainActivity.java, I want to get the profile photo from the database and show it in an ImageView. Problem is that Firebase is asynchronous and it returns immediately, so I can't just call myUser.getFromFirebase() because myUser will still have all null values. I searched a lot but can't find the solution, since I don't want my User class to interact at all with the UI (I want to use a 3-tier methodology).
I tried creating an AsyncTask extension class, but it has the same problem, because the issue is at the User class. I also tried the CountdownLatch approach, but since the value is already on the database, the onDataChange method never gets called at all!!
Does anyone has any idea how to solve this? I'm sure it's extremely easy, because it's not a weird scenario, but I'm so stucked...
2 Answers
2
Create callback listener, like below
public interface OnDataReceiveCallback
void onDataReceived(String display_name, String photo);
Modify method to pass callback
private void getFromFirebase(OnDataReceiveCallback callback)
final FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference reference = database.getReference( FirebaseReferences.USERS ).child( userId );
reference.addValueEventListener( new ValueEventListener()
@Override
public void onDataChange( @NonNull DataSnapshot dataSnapshot )
display_name = dataSnapshot.child( "username" ).getValue( String.class );
photo = dataSnapshot.child( "profile_image" ).getValue( String.class );
callback.onDataReceived(display_name,photo);
@Override
public void onCancelled( @NonNull DatabaseError databaseError )
);
Final call of getFromFirebase
getFromFirebase(new OnDataReceiveCallback()
public void onDataReceived(String display_name, String photo)
// do something
);
I used your approach and got the work done! Thanks so much! What I did to keep the Firebase thing INSIDE my User class is to define the interface, and made the constructor of User accept an interface parameter. Then, the UI needed to do User user = new User ( new InterfaceForCallback() blah blah blah update UI with display_name and photo ) and that's all. So, UI doesn't care if the data is local, in Firebase, or in any other storage. It just know it needs a callback that will get the display_name and photo as parameters. You solved it so easily and clearly!
– Adrián Alvarez
Sep 2 at 11:41
Awesome !! Glad to know that solves the problem
– Krishna Sharma
Sep 2 at 13:54
You will have to arrange for your views to be updated with each callback you receive to onDataChange
. If you don't want your callback to directly modify views, you will need to adopt some form of app architecture to abstract your repository (Realtime Database) from your views.
onDataChange
This is not "extremely easy". Also, you have a lot of choices for app architecture (MVP, MVC, MVVM), and various frameworks to help with this (such as Android's own LiveData). What you are venturing into is highly opinionated, and involves writing a lot more code than you have here.
I can point you to a repository that uses Jetpack's Android Architecture Components as app architecture for a demo app that uses both RTDB and Firestore, but you'll see that it's a lot of lines of code, and it's also just my opinion about how to get things done. You will find lots of other opinions out there.
I'll see the repository! Thank you so much for the clarification!
– Adrián Alvarez
Sep 2 at 11:43
Thanks for contributing an answer to Stack Overflow!
But avoid …
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
But avoid …
To learn more, see our tips on writing great answers.
Required, but never shown
Required, but never shown
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
Have you given a thought to placeholders? Empty strings, mock images, etc.. Then update to the correct asset when it come through.
– James Poag
Sep 1 at 17:01