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

如何强制Paging Library发起API请求刷新数据库数据?

解决PagedList.BoundaryCallback本地有数据时强制刷新网络的问题

你的问题很典型——PagedList的BoundaryCallback设计初衷就是仅在本地数据源为空(onZeroItemsLoaded)或滚动到列表末尾(onItemAtEndLoaded)时触发网络请求,所以本地已有数据时不会自动发起刷新。要实现强制刷新,我们需要给BoundaryCallback添加主动触发的逻辑,结合本地数据清理和分页重置来完成。

下面是具体的实现方案,基于你提供的代码修改:

1. 给BoundaryCallback添加手动刷新方法

修改UpcomingMoviesBoundaryCallback,新增refresh()方法,负责重置分页、清空本地旧数据并触发网络请求:

public class UpcomingMoviesBoundaryCallback extends PagedList.BoundaryCallback<MovieListItemEntity> {
    public static final String TAG = UpcomingMoviesBoundaryCallback.class.getSimpleName();
    private UpcomingMoviesRepository upcomingMoviesRepository;
    private int page = 1;
    private boolean isRefreshing = false; // 防止并发刷新

    public UpcomingMoviesBoundaryCallback(UpcomingMoviesRepository upcomingMoviesRepository) {
        this.upcomingMoviesRepository = upcomingMoviesRepository;
    }

    // 新增手动刷新方法
    public void refresh() {
        if (isRefreshing) return;
        isRefreshing = true;
        page = 1; // 重置分页到第一页

        // 先清空本地旧数据,确保刷新后展示最新内容
        upcomingMoviesRepository.clearUpcomingMovies()
                .subscribeOn(Schedulers.io())
                .subscribe(() -> {
                    load(); // 清空后加载最新第一页数据
                    isRefreshing = false;
                }, error -> {
                    Log.d(TAG, "refresh: 清空本地数据失败", error);
                    isRefreshing = false;
                });
    }

    @Override
    public void onZeroItemsLoaded() {
        super.onZeroItemsLoaded();
        Log.d(TAG, "onZeroItemsLoaded: ");
        load();
    }

    @Override
    public void onItemAtEndLoaded(@NonNull MovieListItemEntity itemAtEnd) {
        super.onItemAtEndLoaded(itemAtEnd);
        Log.d(TAG, "onItemAtEndLoaded: ");
        load();
    }

    @SuppressLint("CheckResult")
    private void load() {
        upcomingMoviesRepository.getUpcoming(page)
                .doOnSuccess(result -> {
                    upcomingMoviesRepository.saveUpcomingMovies(result);
                    page = result.getPage() + 1;
                })
                .subscribeOn(Schedulers.io())
                .subscribe(result -> {
                    Log.d(TAG, "load: 加载第" + result.getPage() + "页成功");
                }, error -> {
                    Log.d(TAG, "load: 加载失败", error);
                });
    }
}

2. 扩展Repository的功能

修改UpcomingMoviesRepositoryImpl,保存BoundaryCallback实例并新增清空本地数据、触发刷新的方法:

public class UpcomingMoviesRepositoryImpl implements UpcomingMoviesRepository {
    private static final String TAG = UpcomingMoviesRepository.class.getSimpleName();
    private MovieResponseMapper movieResponseMapper = new MovieResponseMapper();
    private MovieAppApi mMovieAppApi;
    private UpcomingDao mUpcomingDao;
    private UpcomingMoviesBoundaryCallback boundaryCallback; // 保存BoundaryCallback实例

    public UpcomingMoviesRepositoryImpl(MovieAppApi mMovieAppApi, UpcomingDao mUpcomingDao) {
        this.mMovieAppApi = mMovieAppApi;
        this.mUpcomingDao = mUpcomingDao;
    }

    @Override
    public Single<MovieListResponse> getUpcoming(int page) {
        return mMovieAppApi.upcoming(page);
    }

    @Override
    public Single<MovieListResponse> getUpcoming() {
        return mMovieAppApi.upcoming();
    }

    @Override
    public void saveUpcomingMovies(MovieListResponse movieListResponse) {
        Executors.newSingleThreadExecutor().execute(() -> {
            long[] inserted = mUpcomingDao.save(movieResponseMapper.map2(movieListResponse.getResults()));
            Log.d(TAG, "saveUpcomingMovies: 保存了" + inserted.length + "条数据");
        });
    }

    // 新增:清空本地即将上映电影数据
    public Completable clearUpcomingMovies() {
        return Completable.fromAction(() -> mUpcomingDao.clear())
                .subscribeOn(Schedulers.io());
    }

    // 新增:触发刷新的对外接口
    public void refreshUpcomingMovies() {
        if (boundaryCallback != null) {
            boundaryCallback.refresh();
        }
    }

    @Override
    public LiveData<PagedList<MovieListItemEntity>> getUpcomingLiveData() {
        PagedList.Config config = new PagedList.Config.Builder()
                .setEnablePlaceholders(true)
                .setPageSize(12)
                .build();
        DataSource.Factory<Integer, MovieListItemEntity> dataSource = mUpcomingDao.upcoming();
        boundaryCallback = new UpcomingMoviesBoundaryCallback(this); // 初始化并保存实例
        LivePagedListBuilder builder = new LivePagedListBuilder(dataSource, config)
                .setBoundaryCallback(boundaryCallback);
        return builder.build();
    }
}

3. 在Dao中添加清空数据的方法

给UpcomingDao新增清空表的SQL方法:

@Dao
public interface UpcomingDao {
    // 原有保存、查询方法...
    
    @Query("DELETE FROM upcoming_movies")
    void clear();
}

4. 在业务层触发刷新

在你需要刷新的地方(比如下拉刷新的回调、页面重新可见时)调用Repository的刷新方法:

// 示例:在ViewModel中调用
public class UpcomingMoviesViewModel extends ViewModel {
    private final UpcomingMoviesRepository repository;
    private final LiveData<PagedList<MovieListItemEntity>> upcomingMovies;

    public UpcomingMoviesViewModel(UpcomingMoviesRepository repository) {
        this.repository = repository;
        upcomingMovies = repository.getUpcomingLiveData();
    }

    // 对外暴露刷新方法,供UI层调用
    public void refreshMovies() {
        repository.refreshUpcomingMovies();
    }
}

核心逻辑说明

  • 重置分页:刷新时把page重置为1,确保加载的是最新的第一页数据
  • 清空本地数据:避免旧数据和新数据混合,保证刷新后展示的全是最新内容
  • 并发控制:用isRefreshing标记防止多次触发刷新导致的重复网络请求
  • 兼容原有逻辑:刷新完成后,滑动到列表末尾依然会触发onItemAtEndLoaded加载后续分页数据

内容的提问来源于stack exchange,提问作者Andras Sanislo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 10:17:18