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

简介: 关键字:SmartRefreshLayout使用 下拉刷新 上拉加载 BaseRecyclerviewAdapterHelper前言下拉刷新和上拉加载是每个APP中最基本的功能,这里将这个功能进行整理。

关键字: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;
    }
}

目录
相关文章
|
搜索推荐 Android开发 iOS开发
AppsFlyer 研究(四)OneLink Deep Linking Guide
AppsFlyer 研究(四)OneLink Deep Linking Guide
918 0
|
C++ Windows
VS Code 切换中英文
VS Code 切换中英文
2129 0
VS Code 切换中英文
|
5月前
|
Java Android开发
Android背景颜色滑动渐变效果(上下滑动,左右滑动)
本文分享了一种通过ScrollView实现滑动变色效果的简单方法。主要步骤包括:1) 在布局中添加ScrollView并确保内容可滑动;2) 获取屏幕高度;3) 获取控件高度;4) 使用GradientDrawable设置渐变颜色;5) 根据控件与屏幕高度比例动态调整颜色数量。示例代码展示了如何在滑动时根据比例改变背景颜色,实现流畅的视觉效果。
183 0
|
消息中间件 存储 负载均衡
高并发流量杀手锏:揭秘秒杀系统背后的削峰技术!
本文介绍了秒杀场景下的“削峰填谷”策略,通过消息队列缓冲用户请求,避免高并发对系统造成冲击。文中详细解释了消息队列的工作原理及如何通过预扣减库存和分布式锁确保数据一致性,同时还提出了合理的消息队列配置、高可用性及数据库负载均衡等最佳实践。通过这些技术手段,可有效提升系统的稳定性和用户体验。
644 8
高并发流量杀手锏:揭秘秒杀系统背后的削峰技术!
|
存储 缓存 NoSQL
如何解决Ubuntu server 下 Redis安装报错:“You need tcl 8.5 or newer in order to run the Redis test”.
如何解决Ubuntu server 下 Redis安装报错:“You need tcl 8.5 or newer in order to run the Redis test”.
739 0
|
运维 安全 物联网
物联网设备的安全固件更新机制:保障设备安全的基石
【7月更文挑战第4天】物联网设备的安全固件更新机制是保障设备安全、稳定运行的重要基石。通过建立完善的更新管理制度、定期检查和更新计划、安全验证和兼容性测试、自动化分发和安装、详细的更新记录、数字签名技术、分阶段或分批更新策略、紧急响应计划及加密通信协议等措施,可以显著提高物联网设备固件更新的安全性和可靠性。未来,随着技术的不断进步和应用场景的拓展,物联网设备的安全固件更新机制将不断完善和发展,为物联网系统的稳定运行和数据安全提供更加坚实的保障。
|
XML 存储 Android开发
Android自定义控件 | 小红点的三种实现(下)
上篇介绍了两种实现小红点的方案,分别是多控件叠加和单控件绘制,其中第二个方案有一个缺点:类型绑定。导致它无法被不同类型控件所复用。这篇给出一种新的方案。
750 0
Android自定义控件 | 小红点的三种实现(下)
|
设计模式 SQL 前端开发
2024年阿里Android高级面试题分享,送给正在迷茫的你
2024年阿里Android高级面试题分享,送给正在迷茫的你
|
消息中间件 缓存 架构师
2024年阿里Android高级面试题分享,附学习笔记+面试整理+进阶书籍
2024年阿里Android高级面试题分享,附学习笔记+面试整理+进阶书籍
|
Android开发
Android Studio 控制台中文乱码,解决方案都在这里了,完美解决
Android Studio 控制台中文乱码,解决方案都在这里了,完美解决