SmartRefreshLayout + BaseRecyclerviewAdapterHelper 使用MVP方式实现下拉刷新

关键字:SmartRefreshLayout使用 下拉刷新 上拉加载 BaseRecyclerviewAdapterHelper

前言
下拉刷新和上拉加载是每个APP中最基本的功能,这里将这个功能进行整理。可以作为一个模板代码去使用,这样避免了每次开发都要去思考,直接复制粘贴使用即可。

实现的功能点:
1.使用MVP实现下拉刷新及加载更多;
2.采用懒加载,禁止viewPager预加载,区分出两种刷新:初始化刷新、下拉刷新;
3.采用BaseRecyclerviewAdapterHelper的上拉加载达到更好的上拉加载效果;
4.上拉加载:无数据、加载错误、数据全部加载完成三种视图的区分显示;
5.下拉刷新无数据空视图的展示;

目录

  • 技术方案选型
  • 具体代码
  • 分页字段的理解

利用SmartRefreshLayout实现下拉刷新
利用 baserecyclerviewadapterhelper 实现加载更多

1.Presenter 层,DemoPresenter.java 如下,只列出简要P层获取新闻列表,M层的实现这里就不列出了,这个不是本文重点。

public class DemoPresenter {
  DemoRepository mRepository;

  // 获取新闻列表
  public void getNews(int pageNumber, int loadType){
    mRepository.loadNewsListByTopic(pageNumber, new DemoDataSource.LoadNewsCallback() {
      
      @Override
      public void onNewsLoaded(List<News> newsList) {
        mView.loadSuccess(newsList, loadType);
      }
      
    });
  }
}

布局设置

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#fff"
    android:orientation="vertical">
    
    <!— 这里屏蔽掉加载更多功能 -->
    <com.scwang.smartrefresh.layout.SmartRefreshLayout
        android:id="@+id/refreshLayout"
        android:layout_width=“match_parent"
        app:srlEnableLoadMore="false"
        android:layout_height="match_parent">
        
        <!-- 添加经典下拉头部刷新 -->
        <com.scwang.smartrefresh.layout.header.ClassicsHeader
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:srlAccentColor="@android:color/white" />
        
        <android.support.v7.widget.RecyclerView
            android:id="@+id/recyclerView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="1" />
        
    </ai.botbrain.smartrefresh.layout.SmartRefreshLayout>
</LinearLayout>

代码中设置

public class TestFragment extends BaseFragment implements TestView {
  
  // 标识分页的字段
  private int mPageNum = 0;
  private static final int COUNT = 10;

  private int mRefreshType;//mRefreshType变量名用小写,防止看混淆
  // 首次刷新
  public static final int FIRST_LOAD = 1;
  // 刷新
  public static final int REFRESH = 2;
  // 上拉加载
  public static final int LOAD_MORE = 3;

  private View mNoDataView;

  @BindView(R.id.refreshLayout)
  SmartRefreshLayout mRefreshLayout;
  
  @BindView(R.id.recyclerView)
  PowerfulRecyclerView mRecyclerView;
  
  private MyAdapter mAdapter;
  
  private MyPresenter mPresenter;
  
  @Override
  public void initData() {
    super.initData();
    mAdapter = new MyAdapter();
    // 自定义加载中,加载失败,加载完成的布局
    mAdapter.setLoadMoreView(new CustomLoadMoreView());
  }

  @Override
  public void initView(View rootView) {
    super.initView(rootView);
    mNoDataView = getLayoutInflater().inflate(R.layout.empty_view, (ViewGroup) mRecyclerView.getParent(), false);
  }  

  @Override
  public void initListener() {
    super.initListener();
    
    // 下拉刷新回调
    mRefreshLayout.setOnRefreshListener(refreshLayout -> {
     mPageNum = 0;
     mPresenter.loadDataList(mPageNum, FIRST_LOAD);
    });
    
    // 上拉加载回调
    mAdapter.setOnLoadMoreListener(() -> {
      mPresenter.loadDataList(mPageNum, LOAD_MORE);
    }, mRecyclerView);
    
    mRecyclerView.setAdapter(mAdapter);
    
    // 刚进来的时候来个初始化刷新
    mRefreshLayout.autoRefresh();
  }
  
  @Override
  public void onLoadNewsSuccess(List<Circle> data, int loadType) {
    // 防范空指针发生
    if (ListUtils.isEmpty(data))
      data = new ArrayList<>();    
    
    mPageNum++;
    // int size = data == null ? 0 : data.size();
    int size = data.size();
    
    // mRefreshLayout.finishLoadmore();
    mRefreshLayout.finishRefresh(0);
    
    // 注意:不要忘记添加 break 否则~
    switch (loadType) {
      case FIRST_LOAD:
        mAdapter.initRefresh(data);// 如果data为null这里就会引发空指针
        break;
      case REFRESH:
        mAdapter.initRefresh(data);
        break;
      case LOAD_MORE:
        mAdapter.loadMoreData(data);
        break;
    }
    
    if (mAdapter.getData().size() == 0) {    //空视图情况
      mAdapter.setEmptyView(noDataView);        
    } else if (size == 0) {                  //上拉加载出来的数据为0,认为加载结束
      mAdapter.loadMoreEnd(false);
    } else {//完成了本次加载,还有更多数据(注意逻辑是在else中,这里写错可能导致不停的上拉加载数据)
      mAdapter.loadMoreComplete();
    }
  }
  
  // 加载失败的情况,显示重试页面
  @Override
  public void onLoadNewsError() {
    // 弹出提示
    mTipView.show();
    
    // 如果一开始进入没有数据,显示重试布局
    if (ListUtils.isEmpty(mAdapter.getData)) {
      showRetry();
    } else { // 显示(加载失败,请点我重试)
      mAdapter.loadMoreFail();
    }
    
    // 收起刷新
    mRefreshLayout.finishLoadmore();
    mRefreshLayout.finishRefresh(0);
    
    // 发送加载完成的事件
    ...
  }
  
}

Adapter 中

public class MyAdapter extends BaseMultiItemQuickAdapter<Data, BaseViewHolder> {

  public MyAdapter() {
    // 这里传入null具体看源码
    super(null);
    addItemType(Data.TYPE_STYLE_1, R.layout.item_circle_layout);
  }
  
  // 初始化刷新
  public void initRefresh(List<Circle> circle) {
    this.mData.clear();
    this.mData.addAll(circle);
    notifyDataSetChanged();
  }
  
  // 初始化刷新
  public void initRefresh(List<Circle> circle) {
    this.mData.addAll(circle);
    notifyDataSetChanged();
  }  
  
  // 普通10条
  public void refreshDataNotClear(List<Article> data) {
    mData.addAll(0, data);
    notifyDataSetChanged();
  }
  
  // 加载更多
  public void loadMoreData(List<Circle> circle) {
    this.mData.addAll(circle);
    notifyDataSetChanged();
  }

  @Override
  protected void convert(BaseViewHolder helper, Circle item) {
    int viewType = helper.getItemViewType();
    switch (viewType) {
      case Article.TYPE_LK_LANDSCAPE:
        renderBanner(helper, item);
        break;
      case :
        break;
  }
}

实体类

public class New implements MultiItemEntity {
    
    public static final int TYPE_ONE_PIC = 100;

    private int itemType;

    public void setItemType(int itemType) {
        this.itemType = itemType;
    }

    @Override
    public int getItemType() {
        return itemType;
    }
}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容