Reputation: 431
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...
Upvotes: 2
Views: 2819
Reputation: 2877
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
}
});
Upvotes: 3
Reputation: 317427
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.
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.
Upvotes: 0