Firebase RTDB: Das Lesen von Daten mithilfe der Paginierung ist zu langsam
Posted: 06 Jan 2025, 20:04
Ich benötige ein großes Datenpaket (10 MB) von RTDB. Alle Daten werden im Knoten „stations“ gespeichert. Wenn ich alle Daten in einer einzigen Anfrage erhalte, stürzt meine Android-App manchmal mit der Fehlermeldung „OutOfMemory“ ab. Ich muss also paginiertes Lesen verwenden, habe aber ein Problem damit.
Die Anforderung zum Lesen vollständiger Daten von Stationen dauert in meinem Fall etwa 10–12 Sekunden. Wenn ich jedoch mehrere Anfragen (Paginierung) stelle und 2 MB für eine Seite lese, dauert jede Anfrage ebenfalls etwa 10 Sekunden. Dadurch erhöhte sich die Gesamtzeit zum Abrufen der Stationsdaten von 10 Sekunden (Einzellesevorgang) auf 50 Sekunden (Seitenlesevorgang). Kann ich die Paginierung beschleunigen? Danke.
Struktur:

Regeln:

Paginierungslogik:
Die Anforderung zum Lesen vollständiger Daten von Stationen dauert in meinem Fall etwa 10–12 Sekunden. Wenn ich jedoch mehrere Anfragen (Paginierung) stelle und 2 MB für eine Seite lese, dauert jede Anfrage ebenfalls etwa 10 Sekunden. Dadurch erhöhte sich die Gesamtzeit zum Abrufen der Stationsdaten von 10 Sekunden (Einzellesevorgang) auf 50 Sekunden (Seitenlesevorgang). Kann ich die Paginierung beschleunigen? Danke.
Struktur:

Regeln:

Paginierungslogik:
Code: Select all
private fun fetchDayStationsPaged(dayTag: String, lastNodeId: String? = null, stations: MutableList = mutableListOf(), callback: (data: List, errorMessage: LoadError?) -> Unit){
val path = String.format(TimelineManager.KEY_TIMELINE_STATIONS, dayTag)
val query = if (lastNodeId == null)
database
.getReference(path)
.orderByKey()
.limitToFirst(2000) //1 node takes approx 1KB
else
database
.getReference(path)
.orderByKey()
.startAfter(lastNodeId)
.limitToFirst(2000)
Timber.d("loader recursion stations $dayTag/${stations.size}")
fetchDayStations(query) { data, errorMessage ->
if (errorMessage == LoadError.NotExist)
callback(stations, null)
else if (errorMessage != null)
callback(emptyList(), errorMessage)
else {
stations.addAll(data)
fetchDayStationsPaged(dayTag, data.last().nodeId, stations, callback)
}
}
}
private var loaderDisposable: Disposable? = null
private fun fetchDayStations(ref: Query, callback: (data: List, errorMessage: LoadError?) -> Unit){
loaderDisposable?.dispose()
loaderDisposable = FirebaseHelper
.dbReadAsSingle(ref)
.subscribeOn(AndroidSchedulers.mainThread())
.observeOn(AndroidSchedulers.mainThread())
.doOnDispose {
callback(emptyList(), LoadError.Cancelled)
}
.subscribe ({ snapshot ->
if (snapshot.exists()) {
val stations = mutableListOf()
snapshot.children.forEach { item ->
item.getValue(StationCloud::class.java)?.also { station ->
stations.add(station.copy(nodeId = item.key))
}
}
Timber.d("loader fetchDayStations stations size = ${stations.size}")
callback(stations.toList(), null)
} else
callback(emptyList(), LoadError.NotExist)
}, {
Timber.e(it)
callback(emptyList(), LoadError.CantGet)
})
}
private fun dbReadAsSingle(ref: Query): Single {
return Single.create { emitter ->
ref.get().addOnCompleteListener { task ->
Timber.d("runQueryCloudFirst task succeed = ${task.isSuccessful}")
if (task.isSuccessful && emitter.isDisposed.not()){
Timber.d("runQueryCloudFirst children size = ${task.result.childrenCount}")
emitter.onSuccess(task.result)
} else
task.exception?.also {
//todo check a bug: timeout exception doesn't work when offline
//https://github.com/firebase/firebase-android-sdk/issues/5771
Timber.e(it, "runQueryCloudFirst")
emitter.onError(it)
}
}
}
}