返回

换个思路,RecyclerView 轻松实现数据预加载

Android

在很多场景下,我们需要分页加载数据,比如新闻列表、微博列表等。为了让用户体验更好,我们需要在用户快滑动到底部时就开始加载下一页数据,这样当用户滑动到底部时就可以无缝衔接到下一页数据,不会出现卡顿或白屏的情况。这种无感知的加载方式就叫做预加载。

实现RecyclerView预加载有多种方案,有的比较复杂,有的很强大。而我接下来介绍的这一种,极简,易于理解,而且非常灵活,适合各种业务场景。

首先,你需要定义一个抽象类IDataLoaderIDataLoader抽象了所有网络请求的行为,并定义了几个抽象方法,比如loadDatacancel等。IDataLoader的实现类就是你实际的网络请求类。

public abstract class IDataLoader<T> {

    protected abstract void loadData(int page, LoadCallback<T> callback);

    protected abstract void cancel();

    public interface LoadCallback<T> {

        void onSuccess(List<T> data, int page);

        void onFailure(Throwable e);
    }
}

定义完IDataLoader之后,你可以定义一个RecyclerView.AdapterAdapter中有一个DataLoader的引用,用于加载数据。

public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private IDataLoader<MyData> mDataLoader;
    private List<MyData> mData = new ArrayList<>();

    public MyAdapter(IDataLoader<MyData> dataLoader) {
        this.mDataLoader = dataLoader;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        // ...
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        // ...
    }

    @Override
    public int getItemCount() {
        return mData.size();
    }

    public void loadData(int page) {
        mDataLoader.loadData(page, new IDataLoader.LoadCallback<MyData>() {

            @Override
            public void onSuccess(List<MyData> data, int page) {
                if (page == 1) {
                    mData.clear();
                }
                mData.addAll(data);
                notifyDataSetChanged();
            }

            @Override
            public void onFailure(Throwable e) {
                // ...
            }
        });
    }
}

最后,你需要定义一个RecyclerView.OnScrollListenerOnScrollListener中监听滚动的事件,当用户快滑动到底部时,就调用AdapterloadData方法加载下一页数据。

public class MyOnScrollListener extends RecyclerView.OnScrollListener {

    private MyAdapter mAdapter;

    public MyOnScrollListener(MyAdapter adapter) {
        this.mAdapter = adapter;
    }

    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);
        if (!recyclerView.canScrollVertically(1)) {
            mAdapter.loadData(mAdapter.getItemCount() / 10 + 1);
        }
    }
}

至此,RecyclerView的预加载功能就实现了。这种预加载方式非常简单,易于理解和使用,而且非常灵活,适合各种业务场景。

当然,你也可以使用其他更复杂、更强大的预加载方案,但对于大多数场景来说,这种简单方案已经足够了。