我按照此 Codelab 实现了分页 3。 代码实验室 但是当我创建 UserPagingRepository 时,我遇到数据类不是映射的问题。在 Room DataBase 中,我使用 UserLocal,而我使用 UserRemote 从 api 获取数据。如何将数据从数据层转换到域层(用户类)。
const val NETWORK_PAGE_SIZE = 20
class UserPagingRepository(
private val service: UserApiService,
private val database: UserDatabase
) {
fun getUsersPaging(): Flow<PagingData<User>> {
val pagingSourceFactory = { database.usersDao().getPagingUsers() }
return Pager(
config = PagingConfig(
pageSize = NETWORK_PAGE_SIZE,
enablePlaceholders = false
),
pagingSourceFactory = pagingSourceFactory,
remoteMediator = UserRemoteMediator(service, database)
)
}
}
修复:
pager.flow // Type is Flow<PagingData<User>>.
.map { pagingData ->
pagingData.map { user -> UiModel(user) }
}
在ViewModel中的下游流程中,当您调用分页数据时,在收集之前应用地图。
searchRepo.searchUser(it)
.map { user ->
UserData.asDomainLayer()
}
.cachedIn(viewModelScope)
为了避免表示/UI 层直接依赖于您的数据实体,我编写了一个解决方法来创建直接返回域模型的寻呼机。 以下所有代码都应该位于您的数据层中。
private fun provideMyPager(): Pager<Int, MyModel> {
return Pager(
config = PagingConfig(pageSize = Constants.PAGING_PAGE_SIZE),
remoteMediator = MyRemoteMediator(...).mapped { it.toEntity() },
pagingSourceFactory = {
contactsDb.contactsDao.pagingSource().mapped(
{ entity -> entity.toModel() },
{ model -> model.toEntity() },
)
}
)
}
class MyRemoteMediator(
...
) : RemoteMediator<Int, MyEntity>() {...}
fun <TEntity : Any, TModel : Any> PagingSource<Int, TEntity>.mapped(
mapToModel: (TEntity) -> TModel,
mapToEntity: (TModel) -> TEntity
): PagingSource<Int, TModel> {
return object : PagingSource<Int, TModel>() {
private val wrapped = this@mapped
override fun getRefreshKey(state: PagingState<Int, TModel>): Int? {
val mappedState = mapPagingState(state, mapToEntity)
return wrapped.getRefreshKey(mappedState)
}
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, TModel> {
val loadResult = wrapped.load(params)
val mappedLoadResult = loadResult.run {
when (this) {
is LoadResult.Page -> {
LoadResult.Page(
data.map(mapToModel),
prevKey,
nextKey,
itemsBefore,
itemsAfter
)
}
is LoadResult.Error -> LoadResult.Error(throwable)
is LoadResult.Invalid -> LoadResult.Invalid()
}
}
return mappedLoadResult
}
}
}
fun <TEntity : Any, TModel : Any> RemoteMediator<Int, TEntity>.mapped(
mapToEntity: (TModel) -> TEntity
) : RemoteMediator<Int, TModel> {
return object : RemoteMediator<Int, TModel>() {
override suspend fun load(
loadType: LoadType,
state: PagingState<Int, TModel>
): MediatorResult {
val mappedState = mapPagingState(state, mapToEntity)
return [email protected](loadType, mappedState)
}
}
}
private fun <TModel : Any, TEntity : Any> mapPagingState(
state: PagingState<Int, TEntity>,
mapToModel: (TEntity) -> TModel
) : PagingState<Int, TModel> {
return state.run {
PagingState(
pages = pages.map {
val mappedData = it.data.map(mapToModel)
PagingSource.LoadResult.Page(
mappedData,
it.prevKey,
it.nextKey,
it.itemsBefore,
it.itemsAfter
)
},
anchorPosition = anchorPosition,
config = config,
leadingPlaceholderCount = 0 // TODO if required, use reflection to find this leadingPlaceHolderCount
)
}