Android 分页 RemoteMediator 未加载任何数据

Android paging RemoteMediator not loading any data

我正在尝试为从 Retrofit 服务器和 Room 数据库获取数据的 Jetpack Compose 应用程序设置 Paging 3。我创建了一个 RemoteMediator 来加载我想要的数据。我第一次 运行 该应用程序时,它正确显示了项目列表。但是,任何后续运行都不会显示任何数据,即使数据在服务器上也是如此。我想让数据显示在屏幕上。

经过检查,数据似乎已从 Room 数据库中删除,并且不再调用 RemoteMediator 加载方法。因此可组合项中显示的项目数为 0。我不知道是什么阻止了加载方法的调用。

远程调解器:

@OptIn(ExperimentalPagingApi::class)
class TaskArchiveRemoteMediator(
    private val clock: Clock,
    private val promptDatabase: PromptDatabase,
    private val promptService: PromptService,
) : RemoteMediator<Int, Task>() {
//    override suspend fun initialize(): InitializeAction {
//        val lastRefreshedAt = promptDatabase.taskDao().getLastArchiveRefreshedAt()
//        return if (lastRefreshedAt?.let { isExpired(it, Instant.now(clock)) } == false) {
//            Log.d("TaskArchiveRemoteMediator", "Should not refresh")
//            InitializeAction.SKIP_INITIAL_REFRESH
//        } else {
//            Log.d("TaskArchiveRemoteMediator", "Should refresh")
//            InitializeAction.LAUNCH_INITIAL_REFRESH
//        }
//    }

    override suspend fun load(loadType: LoadType, state: PagingState<Int, Task>): MediatorResult {
        return try {
            Log.d("TaskArchiveRemoteMediator", "loadType $loadType")
            val loadKey = when (loadType) {
                LoadType.REFRESH -> null
                LoadType.PREPEND -> return MediatorResult.Success(endOfPaginationReached = true)
                LoadType.APPEND -> {
                    val remoteKey = getRemoteKeyForLastItem(state)
                    remoteKey?.nextPageKey
                        ?: return MediatorResult.Success(endOfPaginationReached = true)
                }
            }
            val limit = if (loadType == LoadType.REFRESH) {
                state.config.initialLoadSize
            } else {
                state.config.pageSize
            }

            val page = getTaskPage(loadKey, limit)
            Log.d("TaskArchiveRemoteMediator", "page: $page")

            promptDatabase.withTransaction {
                if (loadType == LoadType.REFRESH) {
                    promptDatabase.taskDao().deleteArchive()
                    promptDatabase.taskRemoteKeyDao().deleteAll()
                }

                page.tasks.lastOrNull()?.let {
                    promptDatabase.taskRemoteKeyDao().insert(TaskRemoteKey(it.id, page.nextCursor))
                }

                val tasks = page.tasks.map { it.toTask(Instant.now(clock)) }
                Log.d("TaskArchiveRemoteMediator", "tasks: $tasks")
                promptDatabase.taskDao().insertAll(tasks)
            }

            MediatorResult.Success(endOfPaginationReached = page.nextCursor == null)
        } catch (e: TaskArchivePagingException) {
            Log.e("TaskArchiveRemoteMediator", "archive load error", e)
            MediatorResult.Error(e)
        } catch (e: IOException) {
            Log.e("TaskArchiveRemoteMediator", "archive load error", e)
            MediatorResult.Error(e)
        } catch (e: HttpException) {
            Log.e("TaskArchiveRemoteMediator", "archive load error", e)
            MediatorResult.Error(e)
        }
    }

    private suspend fun getRemoteKeyForLastItem(state: PagingState<Int, Task>) =
        state.lastItemOrNull()?.id?.let { promptDatabase.taskRemoteKeyDao().getById(it) }

    private suspend fun getTaskPage(after: String?, size: Int): TaskPage {
        val response = promptService.getArchive(after, size)
        if (!response.isSuccessful) {
            throw TaskArchivePagingException(response.message())
        }

        return response.body() ?: throw TaskArchivePagingException("Server response has empty body")
    }
}

存储库:

class TaskArchiveRepository @Inject constructor(
    private val clock: Clock,
    private val promptDatabase: PromptDatabase,
    private val promptService: PromptService,
) {
    @OptIn(ExperimentalPagingApi::class)
    fun getArchive(pageSize: Int) =
        Pager(
            PagingConfig(pageSize),
            remoteMediator = TaskArchiveRemoteMediator(clock, promptDatabase, promptService),
        ) {
            promptDatabase.taskDao().getArchive()
        }.flow
}

可组合:

@Composable
fun TaskArchiveScreen(
    setTopBarState: (TopBarState) -> Unit = {},
    navigateToTaskDetails: (String) -> Unit = {},
    taskArchiveViewModel: TaskArchiveViewModel = hiltViewModel(),
) {
    val taskItems = rememberWithLifecycle(taskArchiveViewModel.archive).collectAsLazyPagingItems()
    val hasData = taskItems.loadState.refresh is LoadState.NotLoading && taskItems.itemCount > 0
    Log.d("TaskArchiveScreen", "loadState: ${taskItems.loadState}, itemCount: ${taskItems.itemCount}")
    val overflowActions = if (hasData) {
        val refreshAction = ActionState(
            icon = painterResource(R.drawable.ic_baseline_refresh_24),
            title = stringResource(R.string.refresh_action),
            onClick = taskItems::refresh,
        )
        listOf(refreshAction)
    } else {
        emptyList()
    }
    setTopBarState(
        TopBarState(
            title = stringResource(R.string.task_archive_title),
            navIconType = NavIconType.Menu,
            overflowActions = overflowActions,
        )
    )
    when {
        taskItems.loadState.refresh is LoadState.Loading -> TaskListLoadingContent()
        taskItems.loadState.refresh is LoadState.Error ->
            LoadFailureContent(
                loadFailureMessage = stringResource(R.string.load_task_archive_failure_message),
                reload = taskItems::retry,
            )
        hasData ->
            TaskArchiveDataContent(
                taskItems = taskItems,
                navigateToTaskDetails = navigateToTaskDetails,
            )
        else -> TaskArchiveEmptyContent()
    }
}

如何加载我的分页项?

原来来自服务器的数据格式不正确:(