compass
compass copied to clipboard
Crash in paging when calling adapter#refresh
Hi While testing your paging library I noticed this crash when refreshing page:
java.lang.IllegalStateException: Realm accessed from incorrect thread. in /tmp/realm-java/realm/realm-library/src/main/cpp/io_realm_internal_OsResults.cpp line 461
at io.realm.internal.OsResults.nativeIsValid(Native Method)
at io.realm.internal.OsResults.isValid(OsResults.java:700)
at io.realm.OrderedRealmCollectionImpl.isValid(OrderedRealmCollectionImpl.java:78)
at io.realm.RealmResults.isValid(RealmResults.java:71)
at dev.arunkumar.compass.paging.RealmTiledDataSource._init_$lambda-1(RealmTiledDataSource.kt:111)
at dev.arunkumar.compass.paging.RealmTiledDataSource.$r8$lambda$bRdLcJUylTJ0at1Xd1D1b6ya11s(Unknown Source:0)
at dev.arunkumar.compass.paging.RealmTiledDataSource$$ExternalSyntheticLambda0.onInvalidated(Unknown Source:2)
at androidx.paging.DataSource$invalidateCallbackTracker$1.invoke(DataSource.kt:103)
at androidx.paging.DataSource$invalidateCallbackTracker$1.invoke(DataSource.kt:103)
at androidx.paging.InvalidateCallbackTracker.invalidate$paging_common(InvalidateCallbackTracker.kt:89)
at androidx.paging.DataSource.invalidate(DataSource.kt:395)
at androidx.paging.LegacyPagingSource$2.invoke(LegacyPagingSource.kt:50)
at androidx.paging.LegacyPagingSource$2.invoke(LegacyPagingSource.kt:48)
at androidx.paging.PagingSource$invalidateCallbackTracker$1.invoke(PagingSource.kt:84)
at androidx.paging.PagingSource$invalidateCallbackTracker$1.invoke(PagingSource.kt:84)
at androidx.paging.InvalidateCallbackTracker.invalidate$paging_common(InvalidateCallbackTracker.kt:89)
at androidx.paging.PagingSource.invalidate(PagingSource.kt:336)
at androidx.paging.PageFetcher.generateNewPagingSource(PageFetcher.kt:204)
at androidx.paging.PageFetcher.access$generateNewPagingSource(PageFetcher.kt:31)
at androidx.paging.PageFetcher$generateNewPagingSource$1.invokeSuspend(Unknown Source:15)
(Coroutine boundary)
After further investigation I can see this is the issue
init {
addInvalidatedCallback {
if (realmResults.isValid) {
realmResults.removeChangeListener(realmChangeListener)
}
realm.close()
}
}
addInvalidatedCallback can be called on any thread. So code inside addInvalidatedCallback must be run with RealmExecutor
Thanks for the report, I will check.
This is my workaround.
public fun <T : RealmModel, R : Any> RealmQueryBuilder<T>.asPagingItems(
tag: String = "PagingItemsExecutor",
pagingConfig: PagingConfig = DefaultPagingConfig,
transform: RealmModelTransform<T, R>
): Flow<PagingData<R>> {
val realmQueryBuilder = this
return flow {
emit(RealmDispatcher(tag))
}.flatMapConcat { dispatcher ->
flow {
val factory = RealmTiledDataSource.Factory(
realmQueryBuilder,
transform
)
val pagingSourceFactory = factory.asPagingSourceFactory(dispatcher)
val newFlow = Pager(
config = pagingConfig,
initialKey = 0,
pagingSourceFactory = pagingSourceFactory
).flow.onCompletion { dispatcher.close() }
emit(newFlow)
}.flattenConcat().flowOn(dispatcher)
}
}