You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Paging3+Guava/LiveData时LiveData提前触发且不再更新求助

问题分析与解决方案

你的问题核心在于ListenableFuturePagingSource返回的LoadResult.Page未正确设置prevKey,同时线程池管理不当,导致Paging3无法正确构建分页数据链,进而无法触发LiveData的后续更新。以下是具体修复步骤:

1. 正确设置LoadResult.Page的prevKey

当前你所有分页的prevKey都设为null,这会导致Paging3无法正确跟踪分页的前后依赖关系,无法将新加载的数据合并到PagingData中,自然不会触发LiveData的onChanged回调。修改loadFuture中的返回逻辑:

@Override
public LoadResult<Integer, Product> call() {
    List<Product> productsList = productsRepository.loadProducts(loadParams.getLoadSize(), finalOffSet);
    Integer nextKey = productsList.size() >= loadParams.getLoadSize() ? finalNextPageNumber + 1 : null;
    // 正确设置prevKey:当前页大于1时,prevKey为当前页减1
    Integer prevKey = finalNextPageNumber > 1 ? finalNextPageNumber - 1 : null;
    return new LoadResult.Page<>(productsList, prevKey, nextKey);
}

2. 复用线程池,避免重复创建

每次loadFuture调用时新建线程池会导致线程泄漏,且可能影响Paging对ListenableFuture回调的监听。将线程池改为ProductsPagingSource的成员变量:

public class ProductsPagingSource extends ListenableFuturePagingSource<Integer, Product> {
    private final ProductsRepository productsRepository;
    private final ListeningExecutorService service;
    private Integer initialLoadSize = 0;

    public ProductsPagingSource(ProductsRepository productsRepository) {
        this.productsRepository = productsRepository;
        // 复用固定大小的线程池
        this.service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(2));
    }

    // ... 其他方法不变,loadFuture中直接使用this.service
}

3. 简化Offset计算逻辑

原逻辑过于复杂,容易出错,简化为更直观的写法:

Integer nextPageNumber = loadParams.getKey();
if (nextPageNumber == null) {
    nextPageNumber = 1;
    initialLoadSize = loadParams.getLoadSize();
}

// 简化offset计算
Integer offset;
if (nextPageNumber == 1) {
    offset = 0;
} else {
    // 初始加载的size + 后续每页的size累加
    offset = initialLoadSize + (nextPageNumber - 2) * loadParams.getLoadSize();
}

4. 完善getRefreshKey实现(可选但推荐)

返回合适的刷新key,确保下拉刷新时能从正确的位置加载数据:

@Nullable
@Override
public Integer getRefreshKey(@NonNull PagingState<Integer, Product> pagingState) {
    Integer anchorPosition = pagingState.getAnchorPosition();
    if (anchorPosition == null) {
        return null;
    }
    PagingSource.LoadResult.Page<Integer, Product> anchorPage = pagingState.closestPageToPosition(anchorPosition);
    if (anchorPage == null) {
        return null;
    }
    // 优先基于prevKey计算刷新key,没有则用nextKey
    if (anchorPage.getPrevKey() != null) {
        return anchorPage.getPrevKey() + 1;
    }
    return anchorPage.getNextKey() != null ? anchorPage.getNextKey() - 1 : null;
}

5. 明确配置PagingConfig(可选)

在ViewModel中创建Pager时,明确指定initialLoadSize,避免默认值(pageSize*3)带来的分页偏移问题:

Pager<Integer, Product> pager = new Pager(
        new PagingConfig(
                10,          // pageSize:每页加载数量
                10,          // initialLoadSize:初始加载数量
                false,       // enablePlaceholders:是否启用占位符
                10           // prefetchDistance:预加载距离
        ),
        () -> new ProductsPagingSource(productsRepository)
);

完成以上修改后,Paging3就能正确构建分页数据链,当新数据加载完成时,LiveData会触发onChanged回调,将包含新数据的PagingData传递给Adapter。

内容的提问来源于stack exchange,提问作者Daniel Trindade

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 18:10:32