Search code examples
androidfirebaseandroid-recyclerviewrealmgoogle-cloud-firestore

Set adapter or RecyclerView refresh after Firestore function


I'm populating a realm database table with information from a Cloud Firestore collection. On the first load, the application opens and saves the information but does not display it until I close and open the application.

I need the information to be displayed after it's been written to the realm database. ie without having to close and open the app. I tried doing this by putting them in methods and in order in the onCreate method.

So after it has written all the information to the realm database I want the recyclerview to populate but I don't know how to do that, please help?

ScreenShots

First launch(left) and second launch(right)

Screen1 Screen2

OnCreate:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_edit_import_user);
    RelativeLayout = findViewById(R.id.contentuserimport);
    // initialize realm
    Realm.init(getApplicationContext());
    //SETUP REEALM
    RealmConfiguration defaultConfig = new RealmConfiguration.Builder()
            .schemaVersion(0)
            .build();
    realm=Realm.getInstance(defaultConfig);
    Intent intent = getIntent();
    moduleID = intent.getStringExtra("moduleID");
    moduleName = intent.getStringExtra("moduleName");
    ButterKnife.bind(this);
    init();
    getAssessList();
}

Init():

private void init(){
    linearLayoutManager = new LinearLayoutManager(getApplicationContext(), LinearLayoutManager.HORIZONTAL, false);
    friendList.setLayoutManager(linearLayoutManager);
    db = FirebaseFirestore.getInstance();
    textView1.setText("Assessments - "+moduleName);
    db.collection("assessment").whereEqualTo("module","xbIpNiDXGsIPmb5sTwbH").get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
        @Override
        public void onComplete(@NonNull Task<QuerySnapshot> task) {
            if (task.isSuccessful()) {
                for (QueryDocumentSnapshot document : task.getResult()) {
                    //GET DATA
                    Assessment a=new Assessment(Double.parseDouble(document.get("achieved").toString()),
                            document.get("date").toString(),document.get("desc").toString(),document.get("module").toString(),
                            document.get("time").toString(),Double.parseDouble(document.get("total").toString()),document.get("type").toString(),
                            document.get("weight").toString());
                    //SAVE
                    RealmHelper helper=new RealmHelper(realm);
                    helper.save(a);
                }
            }
        }
    });
    //READ
    RealmHelper helper=new RealmHelper(realm);
    Assessment=helper.retrieve();
    //BIND
    adapter=new AssessAdapter(this,Assessment);
    friendList.setAdapter(adapter);
    adapter.notifyDataSetChanged();
    friendList.setAdapter(adapter);
}

getAssessList():

private void getAssessList(){        
    //RETRIEVE
    RealmHelper helper=new RealmHelper(realm);
    Assessment=helper.retrieve();
    //BIND
    adapter=new AssessAdapter(this,Assessment);
    friendList.setAdapter(adapter);
    adapter.notifyDataSetChanged();
    friendList.setAdapter(adapter);
}

Solution

  • Trying to retrieve the data outside the callback in the way you do, will not work since the onComplete() method has an asynchronous behavior. So you cannot simply use the following line of code:

    Assessment=helper.retrieve();
    

    And expect to retrieve and use the data like so. Firebase APIs are asynchronous, meaning that onComplete() method returns immediately after it's invoked, and the callback from the Task it returns, will be called some time later. There are no guarantees about how long it will take. So it may take from a few hundred milliseconds to a few seconds before that data is available. Because that method returns immediately, the value of your Assessment object you're trying to use it outside the onComplete() method, will not have been populated from the callback yet.

    Basically, you're trying to return a value synchronously from an API that's asynchronous. That's not a good idea. You should handle the APIs asynchronously as intended.

    A quick solve for this problem would be to use the a object that you get from the database only inside the onComplete() method, otherwise I recommend you see the last part of my anwser from this post in which I have explained how it can be done using a custom callback. You can also take a look at this video for a better understanding.