Realm: add PagedList implementation
This commit is contained in:
parent
52ebe74302
commit
82180304ef
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user