compass icon indicating copy to clipboard operation
compass copied to clipboard

Crash in paging when calling adapter#refresh

Open ggajews opened this issue 4 years ago • 3 comments

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)

ggajews avatar Jan 12 '22 12:01 ggajews

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

ggajews avatar Jan 12 '22 15:01 ggajews

Thanks for the report, I will check.

arunkumar9t2 avatar Jan 13 '22 05:01 arunkumar9t2

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)
  }
}

luis-quidd avatar May 04 '23 15:05 luis-quidd