Reputation: 1621
I'm working on a simple APOD app where I display a RecyclerView
of astronomy pictures that the user can scroll through. I enabled FirebaseDatabase.setPersistenceEnabled(true);
so users can use the app offline and to reduce connections/download bandwidth. The problem is if I set FirebaseDatabase.setPersistenceEnabled(true);
, my app startup time is significantly longer (6 seconds enabled vs 1.5 seconds disabled). I understand the first time a user launches the app the load time should be longer (because persistence is set up), but shouldn't every subsequent launch of the app be significantly shorter since it is not querying the online Firebase server?
To keep from loading many rows at once, I fire two SingleValueEventListeners
, one after another. The first one loads 100 rows and loops through the databaseSnapshot using an AsyncTask
, then displays the images. I then call the second SingleValueEventListener
and loop through it the same way. The second SingleValueEventListener
loads the remaining data, from 101 - 7000.
Below is my GlobalApp
class that extends Application
. This is where I enable persistence. The next 2 methods are where I load the data.
Extending Application Class
public class GlobalApp extends Application {
@Override
public void onCreate() {
super.onCreate();
FirebaseDatabase mDatabaseReference = FirebaseDatabase.getInstance();
mDatabaseReference.setPersistenceEnabled(true);
}
}
Initial Load
private void initialLoad() {
databaseReference.child("apod").orderByChild("date").limitToLast(100).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
new LoadFirebase().execute(dataSnapshot);
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
Second Load
private void secondLoad() {
final String secondKey = firebaseKeys.get(firebaseKeys.size() - 1);
databaseReference.child("apod").orderByChild("date").endAt(secondKey).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
new SecondLoadFirebase().execute(dataSnapshot);
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
If I launch the app with FirebaseDatabase.setPersistenceEnabled(true);
, my Logcat
fills with:
04-18 18:22:22.649 2884-2915/com.foo.apod W/CursorWindow: Window is full: requested allocation 1344 bytes, free space 752 bytes, window size 2097152 bytes
04-18 18:22:22.733 2884-2915/com.foo.apod W/CursorWindow: Window is full: requested allocation 1821 bytes, free space 1124 bytes, window size 2097152 bytes
04-18 18:22:22.798 2884-2915/com.foo.apod W/CursorWindow: Window is full: requested allocation 1580 bytes, free space 1516 bytes, window size 2097152 bytes
04-18 18:22:22.868 2884-2915/com.foo.apod W/CursorWindow: Window is full: requested allocation 1574 bytes, free space 656 bytes, window size 2097152 bytes
04-18 18:22:22.920 2884-2915/com.foo.apod W/CursorWindow: Window is full: requested allocation 1455 bytes, free space 228 bytes, window size 2097152 bytes
04-18 18:22:22.973 2884-2915/com.foo.apod W/CursorWindow: Window is full: requested allocation 1579 bytes, free space 1000 bytes, window size 2097152 bytes
04-18 18:22:23.055 2884-2915/com.foo.apod W/CursorWindow: Window is full: requested allocation 1557 bytes, free space 756 bytes, window size 2097152 bytes
04-18 18:22:23.120 2884-2915/com.foo.apod W/CursorWindow: Window is full: requested allocation 1263 bytes, free space 620 bytes, window size 2097152 bytes
Followed by a bunch of GC calls:
04-18 18:22:26.290 2884-2891/com.foo.apod I/art: Background partial concurrent mark sweep GC freed 171401(23MB) AllocSpace objects, 0(0B) LOS objects, 15% free, 85MB/101MB, paused 2.120ms total 151.451ms
04-18 18:22:29.153 2884-2891/com.foo.apod I/art: Background partial concurrent mark sweep GC freed 552106(22MB) AllocSpace objects, 4(1096KB) LOS objects, 15% free, 84MB/100MB, paused 868us total 158.171ms
04-18 18:22:29.647 2884-2891/com.foo.apod I/art: Background sticky concurrent mark sweep GC freed 211953(18MB) AllocSpace objects, 0(0B) LOS objects, 14% free, 85MB/100MB, paused 2.590ms total 114.968ms
04-18 18:22:30.122 2884-2891/com.foo.apod I/art: Background sticky concurrent mark sweep GC freed 482294(17MB) AllocSpace objects, 43(3MB) LOS objects, 3% free, 96MB/100MB, paused 1.440ms total 100.242ms
04-18 18:22:31.091 2884-2906/com.foo.apod V/FA: Inactivity, disconnecting from the service
It seems the problem might be with SQLite since Firebase stores the data there. I added Stetho to my app and tried to view the database in the browser (thinking I was somehow creating duplicates with persistence enabled), but I could not access the database, it showed nothing.
Does anyone have a clue why this is happening? It took forever to find out where the issue was originating.
Please let me know if you need anymore code.
Thanks
Upvotes: 2
Views: 2009
Reputation: 339
I had the same problem and after reading many documentations from firebase I understood that using :
AddSingleValueEventListener
while persistanceMode enabled will not work properly. AddSingleValueEventListener only listens to local memory not from database itself. And it doesnt update until you run:
AddValueEventListener or ChildEventListener
Do not use AddSingleValueEvenetListener. Use only :
AddValueEventListener or ChildEventListener
if persistance mode is enabled
Upvotes: 0
Reputation: 16309
Unfortunately, Firebase Realtime Database does not implement property indexing of its offline queries. If you do a query at a location (/apod in your case), it will need to scan all of the cached data at that location in order to find the matching results, even if there are only a small number (100 or even 1) that match your query. So I think your slowness is likely due to scanning the 7000+ entries you have stored.
As a workaround, if you could organize your data such that you could read at a more granular location (e.g. /apod/2017/04/ with ~30 entries to query over), that would likely speed things up considerably.
Upvotes: 7