[Android] 列表预加载工具类DataPreloader

DataPreloader用于实现列表数据预加载需求。注意这里的预加载是指预加载数据项的详细信息(例如预拉取视频列表里面某些视频的播放地址等),不是指预先拉取更多的列表项。

概念说明

  • 加载窗口preload window:即需要发起预加载的项目的index区间
  • 焦点:即当前外围逻辑所关心的中心点的index,决定了区间的中心

该工具类引入加载窗口的概念(由upperPosition和LowerPosition组成的闭区间),外围调用triggerPreload()传入当前焦点的index,该工具类即回调哪些index离开了加载窗口和哪些index进入了加载窗口(即窗口的变化情况)。外围可以根据回调来进行加载或取消加载。

使用说明

详见代码和注释如下所示:

mPreloader = new DataPreloader();
mPreloader.setDataSource(new DataPreloader.DataSource() {
    @Override
    public int getPreloadWindow(int direction) {
        // 返回窗口的上下界,每次更新窗口都会回调一次,可以根据业务逻辑调整具体值
        if (direction == DataPreloader.PRELOAD_RANGE_LOWER_BOUND) {
            return 2;
        } else if (direction == DataPreloader.PRELOAD_RANGE_UPPER_BOUND){
            return 2;
        } else {
            return -1;
        }
    }
    @Override
    public int getItemCount() {
        return 10;
    }
});
mPreloader.setWindowListener(new DataPreloader.WindowListener() {
    @Override
    public void onEnterPreloadWindow(int position) {
        // position位置的项目进入了preload window,已经进入了的不会再回调
        Log.d(TAG, "onEnterPreloadWindow() called with: position = [" + position + "] " + mPreloader.getFocusPointPosition());
    }
    @Override
    public void onExitPreloadWindow(int position) {
        // position位置的项目离开了preload window,已经离开了的不会再回调
        Log.d(TAG, "onExitPreloadWindow() called with: position = [" + position + "]" + mPreloader.getFocusPointPosition());
    }
});

使用例子如下所示:

// 在适当的时候(例如列表滑动停止的时候),出发preloader更新窗口位置
mPreloader.triggerPreload(position);

    mPreloader = new DataPreloader();
    mPreloader.setDataSource(new DataPreloader.DataSource() {
        @Override
        public int getPreloadWindow(int direction) {
            if (direction == DataPreloader.PRELOAD_RANGE_LOWER_BOUND) {
                return 0; // 只处理后面2个,所以前面的为0
            } else if (direction == DataPreloader.PRELOAD_RANGE_UPPER_BOUND){
                return 2;
            } else {
                return -1;
            }
        }
        @Override
        public int getItemCount() {
            return mDataset.length; // 数据总大小
        }
    });
    mPreloader.setWindowListener(new DataPreloader.WindowListener() {
        @Override
        public void onEnterPreloadWindow(int position) {
            // 列表滑动停止的时候,回调进入预加载窗口的position。
            // 例如,首次滑动停止时,第一个完全可见的item的下标是1,那么这里回调1 

ohne-rezeptkaufen.com

,2,3 } @Override public void onExitPreloadWindow(int position) { // 列表滑动停止的时候,回调离开预加载窗口的position。 // 例如,滑动停止时,第一个完全可见的item的下标是5,假设之前停留的位置是3,那么这里回调6,7(5还在窗口里,所以不回调) } }); mAdapter = new CustomAdapter(mDataset); mRecyclerView.setAdapter(mAdapter); mLayoutManager = new LinearLayoutManager(getActivity()); mRecyclerView.setLayoutManager(mLayoutManager); // 在适当的时候(例如列表滑动停止的时候),出发preloader更新窗口位置 mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { if (newState == RecyclerView.SCROLL_STATE_IDLE) { int position = ((LinearLayoutManager) mLayoutManager).findFirstCompletelyVisibleItemPosition(); mPreloader.triggerPreload(position); } } });

注意: 合理设置区间的upper和lower。例如用于列表预加载时,可只设置upperBound,而lowerBound设置为0,那么该工具类只会回调后面的数据,不会回调前面的数据

源码:https://gist.github.com/legendmohe/651cd418054a53f64bdd105f67265f15

发表评论

您的电子邮箱地址不会被公开。

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据