干净的架构:无法将 PagingSource<Int, Entities> 映射到 PagingSource<RepositoryModel>

sow*_*mia 8 paging clean-architecture android-room android-paging android-paging-3

我的要求是使用干净的架构和离线支持在页面中显示注释。我正在使用 Paging 库进行分页。下面是用于获取笔记的简洁架构图。

在此输入图像描述

注意:请在新选项卡中打开上图并缩放以清晰查看。

我有四层UIUseCaseRepositoryDatasource。我打算抽象数据源的内部实现。为此,我需要NotesEntities在跨越边界之前映射到另一个模型。

class TimelineDao{
    @Transaction
    @Query("SELECT * FROM NotesEntities ORDER BY timeStamp DESC")
    abstract fun getPagingSourceForNotes(): PagingSource<Int, NotesEntities>
}
Run Code Online (Sandbox Code Playgroud)

目前的实施:

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()
    }
}
Run Code Online (Sandbox Code Playgroud)

预期实施:

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() }
    }
}
Run Code Online (Sandbox Code Playgroud)

PagingSource<Int, NotesEntities>我在映射到 时遇到问题PagingSource<Int, NotesRespositoryModel>。据我研究,没有办法映射 PagingSource<Int, NotesEntities>PagingSource<Int, NotesRespositoryModel>

请告诉我是否有一种干净的方法/解决方法来映射分页源对象。如果有人确定目前没有办法的话。也请留下评论。

请注意:我知道分页允许转换PagingData. 下面是在页面中获取注释的代码片段。它映射NotesEntitiesNotesDomainModel. 但后来我想使用NotesRespositoryModel而不是NotesEntitiesin the 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() }
}

Run Code Online (Sandbox Code Playgroud)

我想到的解决方案:

我没有PagingSource直接使用 in Dao,而是考虑创建一个自定义 PagingSource,它调用 Dao 并将 映射NoteEntitiesLocalRepositoryModel.

但随后我需要了解,对数据库的任何更新都不会反映在PagingSource. 我需要在内部处理它。

请让我知道您对此的想法。

Jan*_*ína 0

如何创建一个实现,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
}
Run Code Online (Sandbox Code Playgroud)

那么用法会是这样的:

override fun getNotesPagingSource(): PagingSource<Int, NotesRepositoryModel> {
  return MappingPagingSource(
    originalSource = notesDao.getPagingSourceForNotes(),
    mapper = { it.toNotesRepositoryModel() },
  )
}
Run Code Online (Sandbox Code Playgroud)

关于空pagesPagingState- 将所有加载的页面映射回原始值将过于昂贵,并且房间的分页实现仅使用anchorPosition并且config.initialLoadSize无论如何 - 请参阅此处此处