When storing approximately 5000 sub nodes under a single node, initialising firebase becomes very slow when making use of the offline capabilities. It takes ~30 seconds befo
Initializing means setValue
to that node right? So, initializing 5000 sub nodes under a single node taking ~30s seems very unusual to me. I've worked with almost same size of data under a single node with a far better performance. So I'm not sure about how much attributes you are putting under a single sub-node, but anyway, I guess you need to check the performance again. I think you're using onCompleteListener
on setValue
to calculate the time spent to initialize the data, as the UI view doesn't provide you the exact time and often slower than the actual operation time.
Preferably, I would like to list all (instead of 25 per page) but I understand that this is not possible since there is no Cursor like mechanism (as Android provides for SQLite) available for working with Firebase.
I'm not quite sure about your purpose though, but what I could suggest for these type of cases is to maintain both Sqlite and Firebase database. Let me clarify.
The idea is to maintain the same copy of the Firebase database for a specific user in the user's phone. So that the local database can serve your purpose fully whenever needed. You can query the database and can use CursorLoader
with which you've handful experience.
It has some other advantages too. You can handle the offline sync with your own mechanism. When the internet is down, store the data you want to sync afterwards in your local Sqlite database and then when the connection is up, you'll get a callback in your BroadcastReceiver
. You can easily setValue
the offline data to Firebase then. Firebase makes this simpler of course, but anyway, as you're very much concerned about the performance, you can give this a try.
The behaviour of GC you posted is usual when your application is doing too much work. Firebase basically uses WebSocket
to maintain the connection to the remote database. So I think you need to check if you're keeping unnecessary connections to the Firebase database. Try to use removeListener
when the listeners are no longer necessary.
Does Firebase evaluate the whole database when initializing?
I'm not sure yet what you've meant by initializing, but yes, if you're taking the same node again for setValue
to that node, it replaces the previous data with the new set of data.
So sharding the data so one root node contains at most 200 sub nodes seems to be the answer for now. I'm setting .keepSynced(true) on the shards and this results in much better performance.
In order to present the sharded list in a single recycler view, I created a class FirebaseArrays which is a collection of FirebaseArray that aggregates multiple arrays into a single observable collection.
https://gist.github.com/ndefeijter/2191f8a43ce903c5d9ea69f02c7ee7e9
I also adapted the FirebaseRecyclerAdapter to use a FirebaseArrays as underlying data structure instead of a single FirebaseArray. The interface is extended using some methods to add additional Firebase paths (i.e. shards).
https://gist.github.com/ndefeijter/d98eb5f643b5faf5476b8a611de912c1
These paths are added upon a 'load more' event (e.g. in case endless scrolling).
private void loadMore() {
final View view = getView();
if (null != view) {
final RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
final FirebaseRecyclerAdapter2<Visit, VisitViewHolder> adapter = (FirebaseRecyclerAdapter2<Visit, VisitViewHolder>) recyclerView.getAdapter();
adapter.addQuery(nextQuery());
}
}