Realm: add PagedList implementation

This commit is contained in:
ganfra 2022-07-21 17:07:33 +02:00
parent 52ebe74302
commit 82180304ef
2 changed files with 109 additions and 0 deletions

View File

@ -0,0 +1,67 @@
package org.matrix.android.sdk.internal.database.pagedlist
import androidx.paging.DataSource
import io.realm.kotlin.Realm
import io.realm.kotlin.notifications.UpdatedResults
import io.realm.kotlin.query.RealmQuery
import io.realm.kotlin.query.RealmResults
import io.realm.kotlin.types.RealmObject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancelChildren
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
internal class RealmTiledDataSource<T : RealmObject> internal constructor(
realm: Realm,
queryBuilder: (Realm) -> RealmQuery<T>,
coroutineScope: CoroutineScope
) :
TiledDataSource<T>() {
class Factory<T : RealmObject>(
private val realm: Realm,
private val queryBuilder: (Realm) -> RealmQuery<T>,
private val coroutineScope: CoroutineScope,
) : DataSource.Factory<Int, T>() {
override fun create(): DataSource<Int, T> {
val childScope = CoroutineScope(SupervisorJob() + coroutineScope.coroutineContext)
return RealmTiledDataSource(realm, queryBuilder, childScope)
}
}
private val results: RealmResults<T>
init {
addInvalidatedCallback {
coroutineScope.coroutineContext.cancelChildren()
}
results = queryBuilder(realm).find()
results.asFlow()
.onEach { resultsChange ->
when (resultsChange) {
is UpdatedResults -> invalidate()
else -> Unit
}
}
.launchIn(coroutineScope)
}
override fun countItems(): Int {
return results.size
}
override fun loadRange(startPosition: Int, count: Int): List<T> {
val size = countItems()
if (size == 0) return emptyList()
return buildList {
val endPosition = minOf(startPosition + count, size)
for (position in startPosition until endPosition) {
results.getOrNull(position)?.also { item ->
add(item)
}
}
}
}
}

View File

@ -0,0 +1,42 @@
package org.matrix.android.sdk.internal.database.pagedlist
import android.annotation.SuppressLint
import androidx.paging.PositionalDataSource
@Suppress("DEPRECATION")
public abstract class TiledDataSource<T : Any> : PositionalDataSource<T>() {
public abstract fun countItems(): Int
public abstract fun loadRange(startPosition: Int, count: Int): List<T>?
@SuppressLint("RestrictedApi") // For computeInitialLoadPosition, computeInitialLoadSize
override fun loadInitial(
params: LoadInitialParams,
callback: LoadInitialCallback<T>
) {
val totalCount = countItems()
if (totalCount == 0) {
callback.onResult(emptyList(), 0, 0)
return
}
val firstLoadPosition = computeInitialLoadPosition(params, totalCount)
val firstLoadSize = computeInitialLoadSize(params, firstLoadPosition, totalCount)
val list = loadRange(firstLoadPosition, firstLoadSize)
if (list != null && list.size == firstLoadSize) {
callback.onResult(list, firstLoadPosition, totalCount)
} else {
invalidate()
}
}
override fun loadRange(params: LoadRangeParams, callback: LoadRangeCallback<T>) {
val list = loadRange(params.startPosition, params.loadSize)
if (list != null) {
callback.onResult(list)
} else {
invalidate()
}
}
}