I have an Android chat app, which stores all messages both in local SQLite DB and in the Firebase realtime DB.
When displaying the messages in RecyclerView, I query them from my local DB (as there are some additional data stored locally, that is not stored in the realtime DB).
I need to have a realtime update of the displayed message send and read status, which I get from the realtime DB.
Will it be fine to set a value event listener for each message inside the onBindViewHolder of recycler view?
This way I listen only to changes in the messages that are currently displayed on the screen and don't get the whole list of messages from the server.(exactly what I need)
2 questions: - Is this solution fine or there is a better way? - I need to remove the listeners for items that are already not visible in the recycler view. How do I do that?
I don't use the FirebaseUI (I'm aware that it solves my problem), but I would like to present the data from my local database and not from the server and only get updates on one field from the firebase realtime DB.
Is this solution fine or there is a better way?
Yes and no! I would have suggested you the FirebaseUI which is definitely the best option but you have already mentioned you do not want to use that. So going with the fact of not using FirebaseUI, this seems to be the best option. [I would suggest you to take reviews about this directly from Firebase people who can give you the accurate answer.] You should also know, if you do not remove the callbacks once the view gets out of the screen, you'll end up with hundreds and thousands of listeners, (most of them redundant) dangling and eating up the memory doing really nothing.
I need to remove the listeners for items that are already not visible in the recycler view. How do I do that?
Pretty simple. you can use the onViewDetachedFromWindow(MyViewHolder holder)
method of recyclerView
which gives you the handler which is about to be removed from the view. You can use this call to remove the callback.
How?
followRef.removeEventListener(followListener);
The thing is - You'll need a reference of your callback to remove it from the location. You can do this in two ways. If you have too many different listeners, you can create a hashmap
that can keep a track of all your listeners. Whenever required, you can get the reference of your listener and remove it.
The other way is:
@Override
public void onBindViewHolder(final MyViewHolder holder, int position) {
User user = data.get(position);
holder.name.setText(user.Name);
holder.surname.setText(user.Surname);
holder.id = user.id; //Id is same as the key used to point this user.
holder.followers.setText("Loading..");
DatabaseReference userFollowers = mRef.child(holder.id).child("Followers");
followListener = new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
holder.followers.setText(String.valueOf(dataSnapshot.getValue()));
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
};
userFollowers.addValueEventListener(followListener); //Adds a listener
}
@Override
public void onViewDetachedFromWindow(MyViewHolder holder) {
DatabaseReference followRef = mRef.child(holder.id).child("Followers");
followRef.removeEventListener(followListener); //Removes the listener
super.onViewDetachedFromWindow(holder);
}
The Code might have minor errors, I have written it in accordance with this question. Havent tested. But I hope you got the idea.
The problem: [Even this thing has a minor problem who's best solution I'm still trying to find]: When you close the activity that contains the recyclerView
, the function onViewDetachedFromWindow(MyViewHolder holder)
doesn't get called for the items on screen at that particular time. Hence, whenever the recyclerView
activity ends, it keeps few callbacks (same as the number of visible items on screen) unremoved.
Even I have dived into Firebase Database recently. Any improvements/suggestions to the answer are welcome.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With