Firebase Database users know that there are two basic listeners for listening Data: ValueEventListener
and ChildEventListener
. It works great when
There are several concerns in this question (namely performance, progress indicator, handling new data such as sorting them). Naturally you should come up with a solution that takes into consideration the priority of your requirements. IMO both ValueEventListener
and ChildEventListener
have their use cases:
ChildEventListener
is generally the recommended way of sync'ing lists of objects. This is even mentioned in the documentation on working with lists:
When working with lists, your application should listen for child events rather than the value events used for single objects.
This is because your client only receives the changed child with the specific update (addition or removal) as opposed to the whole list on every update. Therefore, it allows a more granular level of handling of the updates to the list.
ValueEventListener
can be more useful when you need to process the entire list upon modification of a child. This is the case when you have to sort the list in your RecyclerView
. It's much more easier to do this by getting the entire list, sorting it and refresh the data set of the view. On the other hand, using a ChildEventListener
, it's more difficult to do the sorting because you only have access to one specific child in the list per update event.
From a performance point of view, given that even ValueEventListener
is aware of the "delta" while sync'ing the update, I would tend to think of it as less efficient only on the client side, because the client has to do the processing on the entire list, but this is still much better than having the inefficiency at the network side.
Regarding constant refresh and progress indicators, the most important thing to note is that the Firebase database is a realtime database, hence a constant feed of realtime data is an inherent characteristic. If update events are not needed, you can simply use the addListenerForSingleValueEvent
method to read the data only once. You can also use this if you want to display a progress indicator upon loading the first snapshot:
// show progress indicator
postsReference.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
// load initial data set
// hide progress indicator when done loading
}
...
});
When working with collection data on Firebase you should be using:
onChildAdded
onChildChanged
onChildRemoved
onChildMoved
You may not need all of these but I've found that usually onChildAdded
and onChildRemoved
are often essential. You will have to sort and keep track of the data changing in your adapter and pass that back to the RecyclerView on every updated child.
In contrast, you can use the ValueEventListener
and simply update the entire list however like you said, it would mean every update in that list will cause all the objects in the collection to be sent to you which will cost your user data and cost you more bandwidth on Firebase. This isn't recommended if your data will be updating often.
Source
I had the same exact problem (ValueEventListener
vs ChildEventListener
for RecyclerView
in Android).
The solution I used was to combine both this way :
Suppose dbref points to a firebase db location where my posts are.
vel = dbref.addValueEventListener(vel);
dbref.removeEventListener(vel);
.
This is not necessary if you used dbref.addListenerForSingleValueEvent(vel);
in step 1.query = dbref.orderByChild(post.createdat).startAt(System.currentTimeMillis())
query.addChildEventListener(cel);
I would anyday use onchildAdded listener in this case, there are several advantages of it, firstly you have figured out the network operation that is suppose there are 100 posts and even if one gets changed you will get callback of all of them. Whereas in onChildListener you will get callback of the only post that got changed. So what you can do is map the callbacks of firebase with the recycler views methods like this::-
onChildAdded
--> you must cast the dataSnapshot into your class and call recyclerView.notifyItemAdded()
onChildRemoved
--> recyclerView.notifyItemRemoved(int)
onChildChanged
--> recyclerView.notifyItemChanged(int)
onChildMoved
--> (you probably don't need this, it is for ordering/priority)