分享好友 最新动态首页 最新动态分类 切换频道
BaseRecyclerViewAdapterHelper源码解读(四) 上拉加载更多(2)
2024-12-27 03:48

最后希望可以帮助到大家

千千万万要记得:多刷题!多刷题

之前算法是我的硬伤,后面硬啃了好长一段时间才补回来,算法才是程序员的灵魂

篇幅有限,以下只能截图分享部分的资源

(1)多线程(这里以多线程为代表,其实整理了一本JAVA核心架构笔记集

(2)刷的算法题(还有左神的算法笔记

(3)面经+真题解析+对应的相关笔记(很全面

(4)视频学习(部分

ps:当你觉得学不进或者累了的时候,视频是个不错的选择

在这里,最后只一句话:祝大家offer拿到手软

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

@Override public void onLoadMoreRequested() {

mRecyclerView.postDelayed(new Runnable() {

@Override

public void run() {

if (mCurrentCounter >= TOTAL_COUNTER) {

//数据全部加载完毕

mQuickAdapter.loadMoreEnd();

} else {

if (isErr) {

//成功获取更多数据

mQuickAdapter.addData(DataServer.getSampleData(PAGE_SIZE));

mCurrentCounter = mQuickAdapter.getData().size();

mQuickAdapter.loadMoreComplete();

} else {

//获取更多数据失败

isErr = true;

Toast.makeText(PullToRefreshUseActivity.this, R.string.network_err, Toast.LENGTH_LONG).show();

mQuickAdapter.loadMoreFail();

}

}

}

}, delayMillis);

}

}, mReyclerView);

这里可能看的不是很清楚,详情请看官方demo,https://github.com/CymChad/BaseRecyclerViewAdapterHelper/blob/d296d1fb4e7a64b9fa8a2601f3f896d3a9518be5/app/src/main/java/com/chad/baserecyclerviewadapterhelper/PullToRefreshUseActivity.java

加载完成(注意不是加载结束,而是本次数据加载结束并且还有下页数据

mQuickAdapter.loadMoreComplete();

加载失败

mQuickAdapter.loadMoreFail();

加载结束

mQuickAdapter.loadMoreEnd();

设置监听器,开启监听上拉加载


public void setOnLoadMoreListener(RequestLoadMoreListener requestLoadMoreListener,

RecyclerView recyclerView) {

openLoadMore(requestLoadMoreListener);

if (getRecyclerView() == null) {

setRecyclerView(recyclerView);

}

}

private void openLoadMore(RequestLoadMoreListener requestLoadMoreListener) {

this.mRequestLoadMoreListener = requestLoadMoreListener;

mNextLoadEnable = true;

mLoadMoreEnable = true;

mLoading = false;

}

设置什么时候回调?


public void setPreLoadNumber(int preLoadNumber) {

if (preLoadNumber > 1) {

mPreLoadNumber = preLoadNumber;

}

}

先来说简单的,上面这个方法比较简单,属于配置型的方法.

就是设置当列表滑动到倒数第N个Item的时候(默认是1)回调onLoadMoreRequested()方法.待会儿下面会用到这个参数,先放着.

另外,这个方法可以在使用时不必调用,因为已经有默认值了.

@Override

public void onBindViewHolder(K holder, int position) {

//Add up fetch logic, almost like load more, but simpler.

//这里是判断是否需要下拉加载更多

autoUpFetch(position);

//Do not move position, need to change before LoadMoreView binding

//判断是否需要进行上拉加载更多

autoLoadMore(position);

int viewType = holder.getItemViewType();

switch (viewType) {

case 0:

convert(holder, getItem(position - getHeaderLayoutCount()));

break;

case LOADING_VIEW:

mLoadMoreView.convert(holder);

break;

case HEADER_VIEW:

break;

case EMPTY_VIEW:

break;

case FOOTER_VIEW:

break;

default:

convert(holder, getItem(position - getHeaderLayoutCount()));

break;

}

}

private void autoLoadMore(int position) {

// 判断是否可以进行加载更多的逻辑

if (getLoadMoreViewCount() == 0) {

return;

}

//只有在当前列表的倒数mPreLoadNumber个item开始绑定数据时才进行加载更多的逻辑

if (position < getItemCount() - mPreLoadNumber) {

return;

}

//判断当前加载状态,如果不是默认状态(可能正处于 正在加载中 的状态),则不进行加载

if (mLoadMoreView.getLoadMoreStatus() != LoadMoreView.STATUS_DEFAULT) {

return;

}

//设置当前状态:加载中

mLoadMoreView.setLoadMoreStatus(LoadMoreView.STATUS_LOADING);

if (!mLoading) {

mLoading = true;

if (getRecyclerView() != null) {

getRecyclerView().post(new Runnable() {

@Override

public void run() {

//回调 让调用者去处理加载更多的逻辑

mRequestLoadMoreListener.onLoadMoreRequested();

}

});

} else {

mRequestLoadMoreListener.onLoadMoreRequested();

}

}

}

public int getLoadMoreViewCount() {

//参数合法性 加载更多状态

if (mRequestLoadMoreListener == null || !mLoadMoreEnable) {

return 0;

}

//可加载下一页 有无更多数据

if (!mNextLoadEnable && mLoadMoreView.isLoadEndMoreGone()) {

return 0;

}

//当前数据项个数

if (mData.size() == 0) {

return 0;

}

return 1;

}

重点来了,加载更多的主要逻辑就在这里:当在onBindViewHolder()的时候,根据当前item的position位置,然后去判断是否应该执行加载更多.

具体判断逻辑:当一个item第一次进入window界面时,会调用onBindViewHolder()去绑定数据,这个时候我们知道该position的位置,

于是我们就可以这样干:设置一个mPreLoadNumber标志位置( 当列表滑动到倒数第N个Item的时候(默认是1)回调onLoadMoreRequested()方法 ),

当onBindViewHolder()在绑定数据时的position是最后mPreLoadNumber个时,我们即进行加载更多的回调,然后让调用者去处理.

当然,在回调之前,我们需要进行一些判断,确定当前是否可以进行加载更多.

- mRequestLoadMoreListener监听器是否为null,当前是否处于可以加载更多的状态(mLoadMoreEnable标志位控制)

- 当前有无更多数据(这个由外界调用者决定)

- 当前的数据项个数是否为0,如果没有数据项,那就不必加载更多

- 是否进入倒数的那mPreLoadNumber区域

- 判断当前(mLoadMoreView 这是加载更多的View )加载状态,如果不是默认状态(可能正处于 正在加载中 的状态),则不进行加载

好吧,细心的观众可能已经发现了,上面的这种方式其实有一个缺点:当数据项个数小于1屏幕,那么最后倒数的mPreLoadNumber个肯定是可见的,既然可见那么肯定会执行该item的onBindViewHolder(),执行该方法即会判断是否需要执行加载更多,显然这时是符合条件的,于是就会出现数据未满一屏幕会自动回调onLoadMoreRequested()并且还在那里显示正在加载中.

明显,这时不符合我们的需求的.于是官方有一个解决方案.往下看.

public void disableLoadMoreIfNotFullPage() {

//检查当前RecyclerView是否为null

checkNotNull();

disableLoadMoreIfNotFullPage(getRecyclerView());

}

public void disableLoadMoreIfNotFullPage(RecyclerView recyclerView) {

// 设置加载状态为false

setEnableLoadMore(false);

if (recyclerView == null) return;

RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();

if (manager == null) return;

if (manager instanceof LinearLayoutManager) {

final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) manager;

recyclerView.postDelayed(new Runnable() {

@Override

public void run() {

//数据项个数 > 一屏幕,则继续开启load more

if ((linearLayoutManager.findLastCompletelyVisibleItemPosition() + 1) !=

getItemCount()) {

setEnableLoadMore(true);

}

}

}, 50);

} else if (manager instanceof StaggeredGridLayoutManager) {

final StaggeredGridLayoutManager staggeredGridLayoutManager =

(StaggeredGridLayoutManager) manager;

recyclerView.postDelayed(new Runnable() {

@Override

public void run() {

//返回StaggeredGridLayoutManager布局的跨度数

final int[] positions = new int[staggeredGridLayoutManager.getSpanCount()];

//返回每一个跨度(列)的最后一个可见的item的位置 赋值到该数组里面

staggeredGridLayoutManager.findLastCompletelyVisibleItemPositions(positions);

//找出数组中最大的数(即StaggeredGridLayoutManager布局的当前可见的最下面那个item)

int pos = getTheBiggestNumber(positions) + 1;

// 数据项个数 > 一屏幕,则继续开启load more

if (pos != getItemCount()) {

setEnableLoadMore(true);

}

}

}, 50);

}

}

private int getTheBiggestNumber(int[] numbers) {

int tmp = -1;

if (numbers == null || numbers.length == 0) {

return tmp;

}

for (int num : numbers) {

if (num > tmp) {

tmp = num;

}

}

return tmp;

}

public void setEnableLoadMore(boolean enable) {

//之前的状态需要和现在的状态做对比

int oldLoadMoreCount = getLoadMoreViewCount();

mLoadMoreEnable = enable;

int newLoadMoreCount = getLoadMoreViewCount();

if (oldLoadMoreCount == 1) {

if (newLoadMoreCount == 0) {

//之前有 现在没有 需要移除

notifyItemRemoved(getLoadMoreViewPosition());

}

} else {

if (newLoadMoreCount == 1) {

//将加载布局插入

mLoadMoreView.setLoadMoreStatus(LoadMoreView.STATUS_DEFAULT);

notifyItemInserted(getLoadMoreViewPosition());

}

}

}

这段代码我看到在开源项目的讨论区异常热门,好像很多人都遇到了使用disableLoadMoreIfNotFullPage()无效的事件.

可能是他们用错了吧,可能.disableLoadMoreIfNotFullPage()是需要在setNewData()之后调用才有效.

disableLoadMoreIfNotFullPage()里面想做的事情就是:判断是否需要load more,他判断的依据是:

查看当前屏幕内的最底部的那个item的索引是否与总的数据项个数相等.

- 如果相等,那么说明未满一屏幕,不需要开启load more

- 如果不相等,那么说明满了一屏幕,需要开启laod more

创建加载布局item 并 设置加载布局的点击事件


@Override

public K onCreateViewHolder(ViewGroup parent, int viewType) {

K baseViewHolder = null;

this.mContext = parent.getContext();

this.mLayoutInflater = LayoutInflater.from(mContext);

switch (viewType) {

case LOADING_VIEW:

baseViewHolder = getLoadingView(parent);

break;

case HEADER_VIEW:

baseViewHolder = createBaseViewHolder(mHeaderLayout);

break;

case EMPTY_VIEW:

baseViewHolder = createBaseViewHolder(mEmptyLayout);

break;

case FOOTER_VIEW:

baseViewHolder = createBaseViewHolder(mFooterLayout);

break;

default:

baseViewHolder = onCreateDefViewHolder(parent, viewType);

bindViewClickListener(baseViewHolder);

}

baseViewHolder.setAdapter(this);

return baseViewHolder;

}

private K getLoadingView(ViewGroup parent) {

//加载 加载布局

View view = getItemView(mLoadMoreView.getLayoutId(), parent);

//生成baseviewholder

K holder = createBaseViewHolder(view);

//设置加载布局的点击事件

holder.itemView.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

if (mLoadMoreView.getLoadMoreStatus() == LoadMoreView.STATUS_FAIL) {

//之前是加载失败状态时 前去刷新

notifyLoadMoreToLoading();

}

if (mEnableLoadMoreEndClick && mLoadMoreView.getLoadMoreStatus() == LoadMoreView

.STATUS_END) {

//加载更多布局可以被点击 并且 之前状态是结束状态

notifyLoadMoreToLoading();

}

}

});

return holder;

}

public void notifyLoadMoreToLoading() {

//如果当前正在加载中,则不用管

if (mLoadMoreView.getLoadMoreStatus() == LoadMoreView.STATUS_LOADING) {

return;

}

//将加载更多布局的状态设置为默认状态 这样当下面刷新adapter时会回调onBindViewHolder()从而触发

//autoLoadMore()方法去判断是否需要加载更多,这时候刚好又是默认状态是可以更新的,于是就去回调onLoadMoreRequested()方法

mLoadMoreView.setLoadMoreStatus(LoadMoreView.STATUS_DEFAULT);

notifyItemChanged(getLoadMoreViewPosition());

}

这里的目标是给加载更多布局设置点击事件,可以看到其实在代码里面把加载更多布局是直接设置了点击事件的,只是根据不同的状态决定是否需要执行加载更多的逻辑.只有下面2种情况需要去加载更多.

- 之前是加载失败状态时 加载布局被点击

- 之前是结束状态 并且 加载更多布局可以被点击

满足这两种情况时,就把加载布局view的状态设置成默认状态,并且刷新adapter的最后一项(即加载更多布局那一项),这样adapter会回调onBindViewHolder(),而在onBindViewHolder()又调用了autoLoadMore()方法去判断是否需要加载更多,

显然此时是符合条件的,需要刷新,于是回调onLoadMoreRequested(),并且把加载布局的状态改为STATUS_LOADING正在加载的状态,这样加载布局的样式也跟着改变了.

加载完成


注意不是加载结束,而是本次数据加载结束并且还有下页数据

public void loadMoreComplete() {

if (getLoadMoreViewCount() == 0) {

return;

}

//将当前加载状态改为false 表示未在加载

mLoading = false;

//可进行下一页加载

mNextLoadEnable = true;

// 恢复加载更多布局的状态

mLoadMoreView.setLoadMoreStatus(LoadMoreView.STATUS_DEFAULT);

// 告知加载更多布局被更新了,需要刷新一下

notifyItemChanged(getLoadMoreViewPosition());

}

public int getLoadMoreViewPosition() {

return getHeaderLayoutCount() + mData.size() + getFooterLayoutCount();

}

刷新完成之后,需要做一些善后操作,如上所示,代码注释已经很清楚了.

加载失败


public void loadMoreFail() {

if (getLoadMoreViewCount() == 0) {

return;

}

//当前加载状态 切换为未在加载中

mLoading = false;

//加载布局设置为加载失败

mLoadMoreView.setLoadMoreStatus(LoadMoreView.STATUS_FAIL);

//通知加载布局更新了,需要刷新

notifyItemChanged(getLoadMoreViewPosition());

}

就是简单地做一下判断,是否可以继续加载,并且更新布局.

加载结束


public void loadMoreEnd() {

loadMoreEnd(false);

}

public void loadMoreEnd(boolean gone) {

if (getLoadMoreViewCount() == 0) {

return;

}

当前加载状态 切换为未在加载中

mLoading = false;

//不能再加载下一页了 因为已经没有更多数据了

mNextLoadEnable = false;

//设置加载更多布局是否可见

mLoadMoreView.setLoadMoreEndGone(gone);

if (gone) {

//如果布局不可见,则更新

notifyItemRemoved(getLoadMoreViewPosition());

} else {

//如果布局可见,则先更新布局(切换为STATUS_END状态那种布局)

mLoadMoreView.setLoadMoreStatus(LoadMoreView.STATUS_END);

//并更新adapter

notifyItemChanged(getLoadMoreViewPosition());

}

}

设置加载结束,即表示没有更多的数据可以加载了,于是把mNextLoadEnable标志位设为false,表示无法再加载下一页.

然后根据是否需要显示加载布局,进行刷新adapter.

上拉加载布局


在源码里面有一个抽象类LoadMoreView.

public abstract class LoadMoreView {

public static final int STATUS_DEFAULT = 1;

public static final int STATUS_LOADING = 2;

public static final int STATUS_FAIL = 3;

public static final int STATUS_END = 4;

private int mLoadMoreStatus = STATUS_DEFAULT;

private boolean mLoadMoreEndGone = false;

public void setLoadMoreStatus(int loadMoreStatus) {

this.mLoadMoreStatus = loadMoreStatus;

}

public int getLoadMoreStatus() {

return mLoadMoreStatus;

}

public void convert(BaseViewHolder holder) {

//根据不同的状态

switch (mLoadMoreStatus) {

case STATUS_LOADING:

visibleLoading(holder, true);

看完美团、字节、腾讯这三家的一二三面试问题,是不是感觉问的特别多,可能咱们真的又得开启面试造火箭、工作拧螺丝的模式去准备下一次的面试了。

开篇有提及我可是足足背下了Java互联网工程师面试1000题,多少还是有点用的呢,换汤不换药,不管面试官怎么问你,抓住本质即可!能读到此处的都是真爱

  • Java互联网工程师面试1000题

而且从上面三家来看,算法与数据结构是必备不可少的呀,因此我建议大家可以去刷刷这本左程云大佬著作的 《程序员代码面试指南 IT名企算法与数据结构题目最优解》,里面近200道真实出现过的经典代码面试题。

  • 程序员代码面试指南–IT名企算法与数据结构题目最优解
  • 其余像设计模式,建议可以看看下面这4份PDF(已经整理
  • 更多的Java面试学习笔记如下,关于面试这一块,我额外细分出Java基础-中级-高级开发的面试+解析,以及调优笔记等等等。。。

以上所提及的全部Java面试学习的PDF及笔记,如若皆是你所需要的,那么都可发送给你

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

setLoadMoreStatus(int loadMoreStatus) {

this.mLoadMoreStatus = loadMoreStatus;

}

public int getLoadMoreStatus() {

return mLoadMoreStatus;

}

public void convert(BaseViewHolder holder) {

//根据不同的状态

switch (mLoadMoreStatus) {

case STATUS_LOADING:

visibleLoading(holder, true);

看完美团、字节、腾讯这三家的一二三面试问题,是不是感觉问的特别多,可能咱们真的又得开启面试造火箭、工作拧螺丝的模式去准备下一次的面试了。

开篇有提及我可是足足背下了Java互联网工程师面试1000题,多少还是有点用的呢,换汤不换药,不管面试官怎么问你,抓住本质即可!能读到此处的都是真爱

  • Java互联网工程师面试1000题

[外链图片转存中…(img-XNwR2bj8-1715812976014)]

而且从上面三家来看,算法与数据结构是必备不可少的呀,因此我建议大家可以去刷刷这本左程云大佬著作的 《程序员代码面试指南 IT名企算法与数据结构题目最优解》,里面近200道真实出现过的经典代码面试题。

  • 程序员代码面试指南–IT名企算法与数据结构题目最优解

[外链图片转存中…(img-GuGOKhGP-1715812976015)]

  • 其余像设计模式,建议可以看看下面这4份PDF(已经整理

[外链图片转存中…(img-jVXhyGjQ-1715812976015)]

  • 更多的Java面试学习笔记如下,关于面试这一块,我额外细分出Java基础-中级-高级开发的面试+解析,以及调优笔记等等等。。。

[外链图片转存中…(img-UziOg7yn-1715812976015)]

以上所提及的全部Java面试学习的PDF及笔记,如若皆是你所需要的,那么都可发送给你

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

最新文章
常清三仁茶(新零售商城开发)
常清三仁茶app开发找【请注明:黄海专属产品经理对接】常清三仁茶小程序开发,常清三仁茶系统开发,常清三仁茶软件商城开发,常清三仁茶模式平台搭建,常清三仁茶商城系统开发,常清三仁茶新零售系统开发,常清三仁茶模式系统开发【I8.5+ZO
中国古树名木排行榜前十名:最新、最全的十大古树名木大全
中国古树名木排行榜前十名:最新、最全的十大古树名木大全中国古树名木排行榜前十名是一份关于最新、最全的十大古树名木的详细列表。这些古树名木在历、文化、生态和科学价值方面都有着极高的地位对研究中国植物多样性和保护生态环境具有要
搜狗劫持百度神马等流量构成不正当竞争,3000万罚款创海淀法院同类案件最高纪录
图片来源:每经记者 张韵 摄6月27日,海淀法院对奇虎公司、百度公司,以及动景公司和神马公司因搜狗输入法通过搜索候选词为搜狗搜索导流量分别起诉搜狗公司等不正当竞争纠纷三案集中宣判。法院一审认定搜狗公司构成不正当竞争,应停止不正
规则引擎--规则集:规则集合的组织和执行
当弄清楚了一个规则的设计和执行逻辑后,接下来需要考虑的就是许多的规则如何组织了,即规则集的抽象设计。 来看一些例子普通的规则集合使用TreeSet存储规则,具体是依靠规则的priority和name来排序存储到TreeSet中回到
遂昌卫生间渗水到楼下维修电话〈免费上门〉遂昌县洗手间地板渗水
不砸砖、不砸墙;免砸砖防水补漏技术,2小时快速解决漏水问题,超长保修期。漏水维修服务项目:防水查漏、外墙飘窗渗水、玻璃房漏水、房屋墙面起皮、楼顶裂缝漏水、厨房间漏水、飘窗渗水、厂房漏水维修、地下室渗水、地板下暗管漏水、漏水检测
网络安全红队打点打点信息收集思路及教程
网络安全红队在信息收集阶段主要思路是通过各种手段和渠道,收集目标的详细信息,为后续攻击打下基础。网络安全红队打点打点信息收集思路及教程信息收集的主要内容包括域名、子域名、网站、真实IP、敏感目录文件、开放端口和中间件信息等。
Shopee手动关键词&手动关联广告开启“自动优化出价”!
在大促当日,Shopee广告通常有更好的转化率,以及更激烈的出价竞争。如果您没有手动调整出价,或是手动调整的幅度与大盘行情不符,那么您的广告可能会排名偏低,在大促当日无法充分获取黄金的高转化流量,影响当日的广告ROI和销售表现。为
英伟达回应中国反垄断立案;TikTok提交紧急动议阻止封禁法律;ChatGPT新模型会通过欺骗来保护自身
(全球TMT2024年12月10日讯)今日要点:市场监管总局立案调查英伟达;欧盟反垄断监管机构调查英伟达;TikTok提交紧急动议阻止封禁法律;苹果2026年在沙特开设首家零售店;ChatGPT新模型被曝会通过欺骗来保护自身;谷歌新发布量子计算芯片;
谷歌推广开户如何收费? 四大因素影响着你对谷歌推广费用
随着跨境电商的飞速发展,国内市场形成了“不出海,就出局”的竞争格局,划桨出海基本成为多数企业的不二选择。谷歌作为全球顶端的流量入口,自然成为不少企业欢迎的推广途径。外贸企业对于谷歌推广,既关心
必看!这里告诉你如何通过微信广告直播推广方式做大事件营销?
通过腾讯广告直播推广方式做大事件营销,可以遵循以下步骤和策略:一、明确推广目标首先,需要明确推广目标,例如增加品牌知 名度、促进产品销售、引导用户关注视频号直播间等。这些目标将指导整个广告推广过程,包括广告创意的设计、投放
相关文章
推荐文章
发表评论
0评