如何无需特殊手段实现LiveData<PagedList<X>>到LiveData<PagedList<Y>>映射?
解决方案:通过包装数据源工厂实现领域对象到UI对象的分页映射
不用反射、修改分页库或者强行侵入android.arch.paging包的核心思路,是在数据加载链路中插入类型映射逻辑——通过包装原生的PositionalDataSource和DataSource.Factory,在数据从数据源返回时自动完成领域对象(X)到UI对象(Y)的转换,最终生成符合需求的LiveData<PagedList<Y>>。
步骤1:实现映射版的PositionalDataSource
创建一个通用的包装类,继承自PositionalDataSource<Y>,内部持有原生的PositionalDataSource<X>和映射函数,在加载数据的回调中完成类型转换:
Kotlin 示例
class MappingPositionalDataSource<X, Y>( private val originalDataSource: PositionalDataSource<X>, private val mapper: (X) -> Y ) : PositionalDataSource<Y>() { override fun loadInitial(params: LoadInitialParams, callback: LoadInitialCallback<Y>) { originalDataSource.loadInitial(params, object : LoadInitialCallback<X>() { override fun onResult(data: List<X>, position: Int, totalCount: Int) { // 将X列表映射为Y列表后返回 callback.onResult(data.map(mapper), position, totalCount) } }) } override fun loadRange(params: LoadRangeParams, callback: LoadRangeCallback<Y>) { originalDataSource.loadRange(params, object : LoadRangeCallback<X>() { override fun onResult(data: List<X>) { callback.onResult(data.map(mapper)) } }) } }
Java 示例
public class MappingPositionalDataSource<X, Y> extends PositionalDataSource<Y> { private final PositionalDataSource<X> originalDataSource; private final Function<X, Y> mapper; public MappingPositionalDataSource(PositionalDataSource<X> originalDataSource, Function<X, Y> mapper) { this.originalDataSource = originalDataSource; this.mapper = mapper; } @Override public void loadInitial(@NonNull LoadInitialParams params, @NonNull LoadInitialCallback<Y> callback) { originalDataSource.loadInitial(params, new LoadInitialCallback<X>() { @Override public void onResult(@NonNull List<X> data, int position, int totalCount) { List<Y> mappedData = data.stream().map(mapper).collect(Collectors.toList()); callback.onResult(mappedData, position, totalCount); } }); } @Override public void loadRange(@NonNull LoadRangeParams params, @NonNull LoadRangeCallback<Y> callback) { originalDataSource.loadRange(params, new LoadRangeCallback<X>() { @Override public void onResult(@NonNull List<X> data) { List<Y> mappedData = data.stream().map(mapper).collect(Collectors.toList()); callback.onResult(mappedData); } }); } }
步骤2:实现映射版的DataSource.Factory
创建一个包装的DataSource.Factory,用来生成上面的MappingPositionalDataSource,作为原生工厂和映射数据源的桥梁:
Kotlin 示例
class MappingDataSourceFactory<X, Y>( private val originalFactory: DataSource.Factory<Int, X>, private val mapper: (X) -> Y ) : DataSource.Factory<Int, Y>() { override fun create(): DataSource<Int, Y> { val originalDataSource = originalFactory.create() as PositionalDataSource<X> return MappingPositionalDataSource(originalDataSource, mapper) } }
Java 示例
public class MappingDataSourceFactory<X, Y> extends DataSource.Factory<Integer, Y> { private final DataSource.Factory<Integer, X> originalFactory; private final Function<X, Y> mapper; public MappingDataSourceFactory(DataSource.Factory<Integer, X> originalFactory, Function<X, Y> mapper) { this.originalFactory = originalFactory; this.mapper = mapper; } @NonNull @Override public DataSource<Integer, Y> create() { PositionalDataSource<X> originalDataSource = (PositionalDataSource<X>) originalFactory.create(); return new MappingPositionalDataSource<>(originalDataSource, mapper); } }
步骤3:生成映射后的LiveData<PagedList>
最后用包装后的工厂构建LiveData<PagedList<Y>>,完全复用原生的分页配置和边界回调(如果有的话):
Kotlin 示例
// 假设你已有原生的数据源工厂和分页配置 val originalFactory: DataSource.Factory<Int, X> = YourOriginalDataSourceFactory() val pagedListConfig = PagedList.Config.Builder() .setPageSize(20) .setEnablePlaceholders(true) .build() // 转换为LiveData<PagedList<Y>> val mappedFactory = MappingDataSourceFactory(originalFactory) { x -> // 这里编写X到Y的具体映射逻辑 Y(x.id, x.displayName, x.detailInfo) } val mappedLiveData: LiveData<PagedList<Y>> = LivePagedListBuilder(mappedFactory, pagedListConfig) .setBoundaryCallback(yourOriginalBoundaryCallback) // 复用原生边界回调 .build()
Java 示例
// 原生配置 DataSource.Factory<Integer, X> originalFactory = new YourOriginalDataSourceFactory(); PagedList.Config pagedListConfig = new PagedList.Config.Builder() .setPageSize(20) .setEnablePlaceholders(true) .build(); // 转换 MappingDataSourceFactory<X, Y> mappedFactory = new MappingDataSourceFactory<>(originalFactory, x -> { // X到Y的具体映射逻辑 return new Y(x.getId(), x.getDisplayName(), x.getDetailInfo()); }); LiveData<PagedList<Y>> mappedLiveData = new LivePagedListBuilder<>(mappedFactory, pagedListConfig) .setBoundaryCallback(yourOriginalBoundaryCallback) .build();
方案优势
- 完全规避访问限制:所有代码都在你的应用包下,不需要依赖分页库的内部私有实现。
- 保留完整分页特性:原生数据源的分页逻辑、加载状态、边界回调都能完整复用,仅在数据返回时做类型转换。
- 通用可复用:
MappingPositionalDataSource和MappingDataSourceFactory是通用类,可在项目中多次复用不同的X/Y映射场景。
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

