For my application I need to get some data in background from Firestore every 24h. To do so I implemented a CoroutineWorker that will run every 24H triggered when the phone is charging and that the network is good.
Everything works well for most of the user but for a small part of them I got an OutOfMemory from the collection.get().
Some interesting information is that 48% of the crash happened on PIXEL phone it doesn't seems to reflect the market share. (49 other percent being on samsung phone).
Also 46% of the crash are on Android 13 and 41% on Android 12.
Here is the crash :
Fatal Exception: java.lang.OutOfMemoryError: Firestore (24.2.2) ran out of memory. Check your queries to make sure they are not loading an excessive amount of data.
at com.google.firebase.firestore.util.AsyncQueue.lambda$panic$3(AsyncQueue.java:529)
at com.google.firebase.firestore.util.AsyncQueue(AsyncQueue.java)
at com.google.firebase.firestore.util.AsyncQueue$$InternalSyntheticLambda$0.run(AsyncQueue.java:2)
at android.os.Handler.handleCallback(Handler.java:942)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:226)
at android.os.Looper.loop(Looper.java:313)
at android.app.ActivityThread.main(ActivityThread.java:8741)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067)
And this is my Coroutine worker :
@HiltWorker
class DatabaseSyncWorker @AssistedInject constructor(
@Assisted val context: Context,
@Assisted workerParams: WorkerParameters) : CoroutineWorker(context, workerParams) {
override suspend fun doWork(): Result {
// Crash Log here are display on firebase crashlytics
val result = FirebaseFirestore.getInstance().collection("event")
.orderBy("updated", Query.Direction.ASCENDING)
.whereArrayContains("some_array_key", "some_array_value")
.limit(10)
.get().await().documents
// Crash Log here are NOT display on firebase crashlytics
// Doing something with that data here
return Result.success()
}
companion object {
const val TAG = "DatabaseSyncWorker"
fun startIfNeeded(context: Context) {
val constraintBuilder = Constraints.Builder()
.setRequiredNetworkType(NetworkType.UNMETERED)
.setRequiresBatteryNotLow(true)
.setRequiresCharging(true)
val constraints = constraintBuilder.build()
val periodicWorkRequest = PeriodicWorkRequest.Builder(DatabaseSyncWorker::class.java, 24, TimeUnit.HOURS)
.setConstraints(constraints)
.build()
WorkManager.getInstance(context).enqueueUniquePeriodicWork(TAG, ExistingPeriodicWorkPolicy.KEEP, periodicWorkRequest)
}
}
}
My first idea was to reduce the amount of data and implem pagination, but I still got them even when requesting as low as 10 items pear page. I can also see from the crash log that it's crashing at the request of the first page.