我的要求是使用干净的架构以及离线支持在页面中显示注释。 我正在使用 Paging 库进行分页。下面是用于获取笔记的清晰架构图。
注意:请在新选项卡中打开上图并缩放以清晰查看。
我有四层UI、UseCase、Repository和Datasource。我打算抽象数据源的内部实现。为此,我需要在跨越边界之前将
NotesEntities
映射到另一个模型。
class TimelineDao{
@Transaction
@Query("SELECT * FROM NotesEntities ORDER BY timeStamp DESC")
abstract fun getPagingSourceForNotes(): PagingSource<Int, NotesEntities>
}
当前实施:
internal class NotesLocalDataSourceImpl @Inject constructor(
private val notesDao: NotesDao
) : NotesLocalDataSource {
override suspend fun insertNotes(notes: NotesEntities) {
notesDao.insert(NotesEntities)
}
override fun getNotesPagingSource(): PagingSource<Int, NotesEntities> {
return notesDao.getPagingSourceForNotes()
}
}
预期实施:
internal class NotesLocalDataSourceImpl @Inject constructor(
private val notesDao: NotesDao
) : NotesLocalDataSource {
override suspend fun insertNotes(notes: NotesRepositoryModel) {
notesDao.insert(NotesRepositoryModel.toEntity())
}
override fun getNotesPagingSource(): PagingSource<Int, NotesRepositoryModel> {
return notesDao.getPagingSourceForNotes().map{ it.toNotesRepositoryModel() }
}
}
我在将
PagingSource<Int, NotesEntities>
映射到 PagingSource<Int, NotesRespositoryModel>
时遇到问题。据我研究,没有办法映射
PagingSource<Int, NotesEntities>
至 PagingSource<Int, NotesRespositoryModel>
请告诉我是否有一种干净的方法/解决方法来映射分页源对象。如果有人确定现在没有办法的话。也请留下评论。
请注意:我知道分页允许对
PagingData
进行转换。下面是在页面中获取注释的代码片段。它将 NotesEntities
映射到 NotesDomainModel
。但后来我想在 NotesRespositoryModel
中使用 NotesEntities
而不是 NotesRespositoryImpl
,抽象出 NotesEntities
层中的 NotesLocalDataSourceImpl
。
override fun getPaginatedNotes(): Flow<PagingData<NotesDomainModel>> {
return Pager<Int, NotesEntities>(
config = PagingConfig(pageSize = 10),
remoteMediator = NotesRemoteMediator(localDataSource,remoteDataSource),
pagingSourceFactory = localDataSource.getNotesPagingSource()
).flow.map{ it.toDomainModel() }
}
我想到的解决方案:
我没有直接在 Dao 中使用
PagingSource
,而是想创建一个自定义 PagingSource,它调用 Dao 并将 NoteEntities
映射到 LocalRepositoryModel
。
但是我需要明白,对数据库的任何更新都不会反映在
PagingSource
中。我需要在内部处理它。
请告诉我您对此的想法。
创建一个
PagingSource
的实现,将所有调用转发到原始 PagingSource
并执行映射,如下所示:
class MappingPagingSource<Key: Any, Value: Any, MappedValue: Any>(
private val originalSource: PagingSource<Key, Value>,
private val mapper: (Value) -> MappedValue,
) : PagingSource<Key, MappedValue>() {
override fun getRefreshKey(state: PagingState<Key, MappedValue>): Key? {
return originalSource.getRefreshKey(
PagingState(
pages = emptyList(),
leadingPlaceholderCount = 0,
anchorPosition = state.anchorPosition,
config = state.config,
)
)
}
override suspend fun load(params: LoadParams<Key>): LoadResult<Key, MappedValue> {
val originalResult = originalSource.load(params)
return when (originalResult) {
is LoadResult.Error -> LoadResult.Error(originalResult.throwable)
is LoadResult.Invalid -> LoadResult.Invalid()
is LoadResult.Page -> LoadResult.Page(
data = originalResult.data.map(mapper),
prevKey = originalResult.prevKey,
nextKey = originalResult.nextKey,
)
}
}
override val jumpingSupported: Boolean
get() = originalSource.jumpingSupported
}
那么用法会是这样的:
override fun getNotesPagingSource(): PagingSource<Int, NotesRepositoryModel> {
return MappingPagingSource(
originalSource = notesDao.getPagingSourceForNotes(),
mapper = { it.toNotesRepositoryModel() },
)
}
关于
pages
中的空 PagingState
- 将所有加载的页面映射回原始值会太昂贵,并且房间的分页实现仅使用 anchorPosition
和 config.initialLoadSize
- 请参阅 here 和 here。