如何在paging3中的Flow<PagingData<T>>中添加单个项目T?

问题描述 投票:0回答:1

使用 paging3 在 jetpack compose 中实现聊天应用程序接口, 该列表包含消息和日期模块,问题是当我创建一条新消息时,我收到该消息的响应,但现在我想将该消息添加到列表的开头。

@HiltViewModel
class TasklogsViewModel @Inject constructor(
    private val tasklogsRepository: TasklogsRepository,
    savedStateHandle: SavedStateHandle
) : BaseViewModel() {

    private val taskId: Int? = savedStateHandle[TASK_ID_KEY]

    val tasklogsPager = Pager(
        PagingConfig(pageSize = 10)
    ) {
        TasklogsPagingSource(taskId = taskId, tasklogsRepository)
    }.flow.cachedIn(viewModelScope)

    private val _uiState = MutableStateFlow<TasklogsUiState>(TasklogsUiState())
    val uiState: StateFlow<TasklogsUiState> = _uiState

    fun createTasklogs(message: String) = launchIO({

    }) {
        try {
            val request = CreateTasklogRequest(
                content = message,
                type = "TEXT_MESSAGE",
                taskId = taskId!!,
                dateCreated = System.currentTimeMillis()
            )
            when (val res = tasklogsRepository.createTasklog(request)) {
                is NetworkResponse.Error -> {
                    _uiState.update { currentState ->
                        currentState.copy(errorMessage = res.body.message)
                    }
                }

                is NetworkResponse.Success -> {

                }
            }
        } catch (e: Exception) {
            _uiState.update { currentState ->
                currentState.copy(errorMessage = e.message)
            }
        }
    }
}
class TasklogsPagingSource(
    private val taskId: Int?,
    private val tasklogsRepo: TasklogsRepository
) : PagingSource<Int, TasklogsComponentViewData>() {

    override fun getRefreshKey(state: PagingState<Int, TasklogsComponentViewData>): Int? {
        return state.anchorPosition?.let { position ->
            val page = state.closestPageToPosition(position)
            page?.prevKey?.minus(1) ?: page?.nextKey?.plus(1)
        }
    }

    override suspend fun load(params: LoadParams<Int>): LoadResult<Int, TasklogsComponentViewData> {
        return try {
            val page = params.key ?: 0
            if (taskId == null) throw Exception("TaskId is invalid")
            when (val response = tasklogsRepo.getTasklogs(taskId, page)) {
                is NetworkResponse.Error -> {
                    LoadResult.Error(Exception(response.body.message))
                }

                is NetworkResponse.Success -> {
                    val tasklogsList = mutableListOf<TasklogsComponentViewData>()
                    response.successBody.data.forEach { moduleData ->
                        when (moduleData.moduleId) {
                            "task_logs" -> {
                                val taskLog =
                                    (moduleData.data as LogEntity.TasklogEntity).toTasklogViewData()
                                tasklogsList.add(taskLog)
                            }

                            "log_date" -> {
                                val logDate =
                                    (moduleData.data as LogEntity.LogDateEntity).toLogDateViewData()
                                tasklogsList.add(logDate)
                            }
                        }
                    }
                    LoadResult.Page(
                        data = tasklogsList,
                        prevKey = null,
                        nextKey = if (response.successBody.data.isNotEmpty()) response.successBody.paginationKey else null
                    )
                }
            }
        } catch (e: Exception) {
            LoadResult.Error(e)
        }
    }
}

实际上无法找到解决方案,但想到再次强制获取列表,但我不想这样做。

android kotlin pagination android-jetpack-compose android-paging-3
1个回答
0
投票

您面临的问题是您直接从网络上进行分页,只有当页面在网络上发生更改时,您才必须再次拉取页面才有意义。

您应该研究类似

RemoteMediator
https://developer.android.com/reference/kotlin/androidx/paging/RemoteMediator

解决方案是添加本地数据库作为

PagingSource
,而不是直接添加 Web 服务。

来自 Web 服务的响应将填充数据库,对数据库的任何更改都会引发寻呼机运行。

当用户首次进入包含所有消息的页面时,您将使用

RemoteMediator
,这将填充数据库,从而将数据分页到屏幕。

每当您确定用户有新消息时,您都会执行相同的操作,当您收到消息时,将其插入数据库,寻呼机就会执行其操作。

此解决方案允许您的寻呼机仅关注数据库中的内容,这使得下游的一切变得更加简单。

© www.soinside.com 2019 - 2024. All rights reserved.