Adrián Alvarez
Adrián Alvarez

Reputation: 431

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...

Upvotes: 2

Views: 2819

Answers (2)

Krishna Sharma
Krishna Sharma

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

Doug Stevenson
Doug Stevenson

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

Related Questions