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
,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