Android技术知识Android 基础知识Android开发经验谈

使用LoadMoreWrapper为RecyclerView实现

2018-08-16  本文已影响235人  耀东wang

在我们实际的业务需求中,如果是数据比较多,我们一般是采用分页请求,然后在客户端进行分页展示。这里笔者使用了一个叫LoadMoreWrapper这个分页加载框架,使用起来很方便,基本上不用去对RecyclerView的Adapter进行什么操作。

1、添加依赖

首先我们在app中的 build.gradle中添加对应的依赖:

 //LoadMoreWrapper,可以为RecyclerView设置分页加载
    implementation 'com.github.nukc:loadmorewrapper:v1.7.0'

另外我们在主工程的build.gradle中的allprojects中做如下改动

 maven { url "https://jitpack.io" }

看源码

public class LoadMoreWrapper {

    private final LoadMoreAdapter mLoadMoreAdapter;

    public LoadMoreWrapper(LoadMoreAdapter loadMoreAdapter) {
        mLoadMoreAdapter = loadMoreAdapter;
    }

    public static LoadMoreWrapper with(RecyclerView.Adapter adapter) {
        LoadMoreAdapter loadMoreAdapter = new LoadMoreAdapter(adapter);
        return new LoadMoreWrapper(loadMoreAdapter);
    }

    public LoadMoreWrapper setFooterView(@LayoutRes int resId) {
        mLoadMoreAdapter.setFooterView(resId);
        return this;
    }

    public LoadMoreWrapper setFooterView(View footerView) {
        mLoadMoreAdapter.setFooterView(footerView);
        return this;
    }

    public View getFooterView() {
        return mLoadMoreAdapter.getFooterView();
    }

    public LoadMoreWrapper setNoMoreView(@LayoutRes int resId) {
        mLoadMoreAdapter.setNoMoreView(resId);
        return this;
    }

    public LoadMoreWrapper setNoMoreView(View noMoreView) {
        mLoadMoreAdapter.setNoMoreView(noMoreView);
        return this;
    }

    public View getNoMoreView() {
        return mLoadMoreAdapter.getNoMoreView();
    }

    public LoadMoreWrapper setLoadFailedView(@LayoutRes int resId) {
        mLoadMoreAdapter.setLoadFailedView(resId);
        return this;
    }

    public LoadMoreWrapper setLoadFailedView(View view) {
        mLoadMoreAdapter.setLoadFailedView(view);
        return this;
    }

    public View getLoadFailedView() {
        return mLoadMoreAdapter.getLoadFailedView();
    }

    /**
     * 监听加载更多触发事件
     * @param listener {@link com.github.nukc.LoadMoreWrapper.LoadMoreAdapter.OnLoadMoreListener}
     */
    public LoadMoreWrapper setListener(LoadMoreAdapter.OnLoadMoreListener listener) {
        mLoadMoreAdapter.setLoadMoreListener(listener);
        return this;
    }

    /**
     * 设置是否启用加载更多
     * @param enabled default true
     */
    public LoadMoreWrapper setLoadMoreEnabled(boolean enabled) {
        mLoadMoreAdapter.setLoadMoreEnabled(enabled);
        if (!enabled) {
            mLoadMoreAdapter.setShouldRemove(true);
        }
        return this;
    }

    /**
     * 设置全部加载完后是否显示没有更多视图
     * @param enabled default false
     */
    public LoadMoreWrapper setShowNoMoreEnabled(boolean enabled) {
        mLoadMoreAdapter.setShowNoMoreEnabled(enabled);
        return this;
    }

    /**
     * 设置加载失败
     */
    public void setLoadFailed(boolean isLoadFailed) {
        mLoadMoreAdapter.setLoadFailed(isLoadFailed);
    }

    /**
     * 获取原来的 adapter
     */
    public RecyclerView.Adapter getOriginalAdapter() {
        return mLoadMoreAdapter.getOriginalAdapter();
    }

    public LoadMoreAdapter into(RecyclerView recyclerView) {
        recyclerView.setAdapter(mLoadMoreAdapter);
        return mLoadMoreAdapter;
    }
}

可以看到通过本类提供的with方法,LoadMoreWrapper能够实现对Adapter的装饰。里面有很多方法,都有注释,所以我们需要实现的功能用起来也很方便。

3.具体使用

LoadMoreWrapper.with(generateAdapter)
                .setFooterView(R.layout.item_load_more)//底部view
                .setNoMoreView(R.layout.item_load_complete)//没有更多的提示
                .setLoadFailedView(R.layout.item_load_failed)//加载失败的提示
                .setShowNoMoreEnabled(true)
                .setListener(new OnLoadMoreListener() {
                    @Override
                    public void onLoadMore(LoadMoreAdapter.Enabled enabled) {
                        loadMoreEnabled =  enabled;
                        presenter.getData(new PageParmForm(Constant.key,Constant.limit,Constant.order,Constant.page,Constant.sidx),NetWorkActivity.this);
                    }
                })
                .into(mRecyclerView);

使用起来也是很简单的,我们只需要对请求所得到的数据进行判断,然后对请求页码进行自增,就可以实现分页加载显示。

 @Override
    public void showApplicationList(UserGuideSoftConfigRForm<List<UserguideSoftConfig>> Response) {

        data=Response.getData();
        if(pageIndex == 1){
            generateAdapter.setData(data);//直接显示当前页得items
            generateAdapter.notifyDataSetChanged();//更新数据
        }else{//页码不为1得时候
            generateAdapter.addData(data);
        }
        //页码设置,每次获取到数据后,先判断数据集合是否不为空,如果不为空就先使得页码加一,然后下次获取数据的时候再进行判断
        //直到如果数据为空的时候就显示没有更多数据了
        if(data.size() > 0){
            pageIndex ++;
            Constant.page = pageIndex;
        }else{
            //没有更多数据了
            loadMoreEnabled.setLoadMoreEnabled(false);//停止加载更多数据
            generateAdapter.notifyItemChanged(generateAdapter.getData().size());//更新指定位置,Adapter一般有得到数据和设置数据
        }
    }

当没有数据的时候我们要调用

generateAdapter.notifyItemChanged(generateAdapter.getData().size());//更新指定位

可能有人会问为什么是generateAdapter.getData().size()而不是generateAdapter.getData().size() -1呢,是因为在没有数据可以展示的时候,提示View会占一个Item,只有这样,这个提示Item才会生效。
这样就实现了分页加载与显示了。


RecyclerView.PNG

改进与问题

在使用LoadMoreWrapper时,笔者进行了一番改动,结果发现在调用
generateAdapter.notifyItemChanged(generateAdapter.getData().size());是出现了一下错误:

Called attach on a child which is not detached: ViewHolder{40e612c0 position=2 id=-1, oldPos=-1, pLpos:-1 no parent}

自己摸索了半天最终找到了解决方案:

1.第一步:

((SimpleItemAnimator) mRecyclerView.getItemAnimator()).setSupportsChangeAnimations(true);

2.第二步:

我们直接生命一个LoadMoreAdapter,便于在操作过程中对他进行各种设置

 private LoadMoreAdapter mLoadMoreWrapper;
...
   //设置分页加载器
        mLoadMoreWrapper = LoadMoreWrapper.with(generateAdapter)
                .setFooterView(R.layout.item_load_more)//底部view
                .setNoMoreView(R.layout.item_load_complete)//没有更多的提示
                .setLoadFailedView(R.layout.item_load_failed)//加载失败的提示
                .setLoadMoreEnabled(true)
                .setShowNoMoreEnabled(isShowMore)//是否显示没有更多提示页
                .setListener(new OnLoadMoreListener() {
                    @Override
                    public void onLoadMore(LoadMoreAdapter.Enabled enabled) {
                        loadMoreEnabled = enabled;//enable为引用
                        //调用业务
                        presenter.getData(new PageParmForm(Constant.key,Constant.limit,Constant.order,Constant.page,Constant.sidx),NetWorkActivity.this);
                    }
                })
                .into(mRecyclerView);
...
@Override
    public void showApplicationList(UserGuideSoftConfigRForm<List<UserguideSoftConfig>> Response) {

        data=Response.getData();//得到应用列表

        if(pageIndex == 1){

            generateAdapter.setData(data);//直接显示当前页得items

        }else{
            //页码不为1得时候
            generateAdapter.addData(data);
        }

        if( data.size()<10 && pageIndex == 1 )
        {
            //停止加载更多
            mLoadMoreWrapper.setShowNoMoreEnabled(false);
            loadMoreEnabled.setLoadMoreEnabled(false);//停止加载更多数据

        }else if(data.size()>0){

            pageIndex ++;
            Constant.page = pageIndex;
            loadMoreEnabled.setLoadMoreEnabled(true);//加载更多数据

        }else {
            //没有更多数据了
            loadMoreEnabled.setLoadMoreEnabled(false);//停止加载更多数据
            mLoadMoreWrapper.setShowNoMoreEnabled(true);
            generateAdapter.notifyItemChanged(generateAdapter.getData().size());//更新指定位置,Adapter一般有得到数据和设置数据

        }
    }

这样就解决了这个问题,而且对这个Wrapper能达到比较好的控制效果。

上一篇 下一篇

猜你喜欢

热点阅读