Android Paging 3 PagingDataAdapter.refre sh (), за которым следует retry (), вызывает исключение IllegalStateException: невозможно вызвать подсказку, если ни одна страница не загружена - PullRequest
1 голос
/ 21 июня 2020

Я реализую подкачку из сети + кеш базы данных, используя новую библиотеку Paging 3 . Моя реализация похожа на пример Android Paging codelab . Наиболее существенное различие заключается в том, что я хочу отображать данные БД сразу во время загрузки сетевых данных. Я реализовал RemoteMediator и использую PagingSource, предоставленный базой данных Room.

@Dao
interface FooDao {
  ...
  
  @Query("SELECT * FROM foo")
  fun getFooSource(): PagingSource<Int, Foo>
}

По умолчанию данные не отображаются в RecycleView, если нет сетевого подключения. Чтобы сразу отображать данные БД из PagingSource, мой RemoteMediator использует InitializeAction.SKIP_INITIAL_REFRESH, и это решает проблему.

class MyRemoteMediator(...) : RemoteMediator<Int, Foo>() {
  ...

  override suspend fun initialize(): InitializeAction {
    return InitializeAction.SKIP_INITIAL_REFRESH
  }
}

Теперь данные БД отображаются сразу, но сетевые данные не загружаются, поэтому я использую PagingDataAdapter.refresh() метод для запуска запроса. Я не уверен, где правильное место для вызова refresh(), это не сработает, если я позвоню, например, внутри Fragment.onCreate(), поэтому давайте отложим вызов. Я не думаю, что это правильный путь, просто для примера:

class MyFragment : Fragment() {
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    lifecycleScope.launch {
      delay(1000)
      adapter.refresh()
    }
  }
}

Теперь он работает почти так, как ожидалось, данные БД отображаются сразу, а RemoteMediator загружает данные из сети и обновляет базу данных. Единственная проблема, если нет inte rnet access RemoteMediator запрос не выполняется и возвращает MediatorResult.Error. Если я повторю запрос позже, используя метод PagingDataAdapter.retry(), при прокрутке списка я получаю следующую ошибку:

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.icesmith.tvprogramepg, PID: 6381
    java.lang.IllegalStateException: Cannot coerce hint when no pages have loaded
        at androidx.paging.PagerState.withCoercedHint$paging_common(PagerState.kt:313)
        at androidx.paging.PageFetcherSnapshot.doLoad(PageFetcherSnapshot.kt:369)
        at androidx.paging.PageFetcherSnapshot$startConsumingHints$2$invokeSuspend$$inlined$collect$1.emit(Collect.kt:137)
        at kotlinx.coroutines.flow.FlowKt__ChannelsKt.emitAllImpl$FlowKt__ChannelsKt(Channels.kt:59)
        at kotlinx.coroutines.flow.FlowKt__ChannelsKt$emitAllImpl$1.invokeSuspend(Unknown Source:11)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:56)
        at kotlinx.coroutines.EventLoop.processUnconfinedEvent(EventLoop.common.kt:69)
        at kotlinx.coroutines.DispatchedTaskKt.resumeUnconfined(DispatchedTask.kt:184)
        at kotlinx.coroutines.DispatchedTaskKt.dispatch(DispatchedTask.kt:108)
        at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume(CancellableContinuationImpl.kt:306)
        at kotlinx.coroutines.CancellableContinuationImpl.completeResume(CancellableContinuationImpl.kt:393)
        at kotlinx.coroutines.channels.AbstractChannel$ReceiveElement.completeResumeReceive(AbstractChannel.kt:888)
        at kotlinx.coroutines.channels.ConflatedChannel.offerInternal(ConflatedChannel.kt:62)
        at kotlinx.coroutines.channels.ConflatedBroadcastChannel$Subscriber.offerInternal(ConflatedBroadcastChannel.kt:295)
        at kotlinx.coroutines.channels.ConflatedBroadcastChannel.offerInternal(ConflatedBroadcastChannel.kt:257)
        at kotlinx.coroutines.channels.ConflatedBroadcastChannel.offer(ConflatedBroadcastChannel.kt:238)
        at androidx.paging.PageFetcherSnapshot.addHint(PageFetcherSnapshot.kt:179)
        at androidx.paging.PageFetcher$PagerUiReceiver.addHint(PageFetcher.kt:108)
        at androidx.paging.PagingDataDiffer.get(PagingDataDiffer.kt:113)
        at androidx.paging.AsyncPagingDataDiffer.getItem(AsyncPagingDataDiffer.kt:241)
        at androidx.paging.PagingDataAdapter.getItem(PagingDataAdapter.kt:150)
        at com.icesmith.tvprogramepg.fragment.channellist.ChannelAdapter.onBindViewHolder(ChannelAdapter.kt:31)
        at com.icesmith.tvprogramepg.fragment.channellist.ChannelAdapter.onBindViewHolder(ChannelAdapter.kt:13)
        at androidx.recyclerview.widget.RecyclerView$Adapter.onBindViewHolder(RecyclerView.java:7163)
        at androidx.recyclerview.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:7243)
        at androidx.recyclerview.widget.RecyclerView$Recycler.tryBindViewHolderByDeadline(RecyclerView.java:6110)
        at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6376)
        at androidx.recyclerview.widget.GapWorker.prefetchPositionWithDeadline(GapWorker.java:288)
        at androidx.recyclerview.widget.GapWorker.flushTaskWithDeadline(GapWorker.java:345)
        at androidx.recyclerview.widget.GapWorker.flushTasksWithDeadline(GapWorker.java:361)
        at androidx.recyclerview.widget.GapWorker.prefetch(GapWorker.java:368)
        at androidx.recyclerview.widget.GapWorker.run(GapWorker.java:399)
        at android.os.Handler.handleCallback(Handler.java:883)
        at android.os.Handler.dispatchMessage(Handler.java:100)
        at android.os.Looper.loop(Looper.java:214)
        at android.app.ActivityThread.main(ActivityThread.java:7356)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)

...