RecyclerView 局部刷新的坑(1),安卓面试问题和答案

public void onProgress(long finished, long total, int progress) {
XLog.e(mInfoBean.getDownLoadUrl() + “-----------||||||” + progress);
String downloadPerSize = Kits.File.getDownloadPerSize(finished, total);
mInfoBean.setDownLoadStatus(STATUS_DOWNLOADING);
mInfoBean.setDownloadPerSize(downloadPerSize);
mInfoBean.setProgress(progress);
if (isCurrentListViewItemVisible(mPosition)) {
mTestDownLoadAdapter.setProgress(progress, mPosition, downloadPerSize);
}
}

适配器中暴露的用于更新progressBar进度的方法

/**

  • 暴露用于修改进度值的方法
  • @param progress
  • @param position
  • @param progressStr
    */
    public void setProgress(int progress, int position, String progressStr) {
    data.get(position).setProgress(progress);
    data.get(position).setDownloadPerSize(progressStr);
    notifyItemChanged(position);
    }

适配器的onBindViewHolder()中处理数据结果

@Override
public void onBindViewHolder(final TestDownLoadHolder holder, final int position) {
final AppInfoBean appInfoBean = data.get(position);
if (appInfoBean != null) {
ILFactory.getLoader().loadNet(holder.mIvDownPic, appInfoBean.getDownLoadPic(), ImgOptions.getDefImaOptions());
holder.mPbDownProgress.setProgress(appInfoBean.getProgress());
holder.mBtDownLoad.setText(appInfoBean.getDownloadPerSize());
holder.mBtDownLoad.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (getRecItemClick() != null) {
getRecItemClick().onItemClick(position, appInfoBean, 0, holder);
}
}
});
}

}

这里我们使用的是notifyItemChanged局部刷新而不是notifyDataSetChanged。讲道理我们到了这一步就已经可以满足需求了,然而…事实不讲道理:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

一闪一闪亮晶晶

额…原谅demo画得太丑了。这里我们可以发现…为毛我的图片…一闪一闪的,亮瞎我的狗眼了。
至于为什么会闪动?
猜测:

  1. ImageView的宽高问题,重新计算导致了闪动
  2. 更新到了ImageView,然后glide又重新加载了一次图片。
  3. 刷新到了ImageView,这个item渲染了一次。

解疑:

  • 采用了写死宽高的方法,但是!页面还是会闪动…gif就不传了,录制好麻烦。猜测1已经否决了。

ILFactory.getLoader().loadNet(holder.mIvDownPic, appInfoBean.getDownLoadPic(), ImgOptions.getDefImaOptions());

android:src=“@mipmap/ic_launcher”

  • 重新理下,我们需要更新的是Button和progressBar,其实ImageView我们是不需要额外去更新的。

那我们的问题就聚焦在如何只更新一部分控件,其他控件不动

解决

至于怎么解决呢…扒源码:

/**

  • Notify any registered observers that the item at position has changed.
  • Equivalent to calling notifyItemChanged(position, null);.
  • This is an item change event, not a structural change event. It indicates that any

  • reflection of the data at position is out of date and should be updated.
  • The item at position retains the same identity.
  • @param position Position of the item that has changed
  • @see #notifyItemRangeChanged(int, int)
    */
    public final void notifyItemChanged(int position) {
    mObservable.notifyItemRangeChanged(position, 1);
    }

/**

  • Notify any registered observers that the item at position has changed with an
  • optional payload object.
  • This is an item change event, not a structural change event. It indicates that any

  • reflection of the data at position is out of date and should be updated.
  • The item at position retains the same identity.
  • Client can optionally pass a payload for partial change. These payloads will be merged
  • and may be passed to adapter’s {@link #onBindViewHolder(ViewHolder, int, List)} if the
  • item is already represented by a ViewHolder and it will be rebound to the same
  • ViewHolder. A notifyItemRangeChanged() with null payload will clear all existing
  • payloads on that item and prevent future payload until
  • {@link #onBindViewHolder(ViewHolder, int, List)} is called. Adapter should not assume
  • that the payload will always be passed to onBindViewHolder(), e.g. when the view is not
  • attached, the payload will be simply dropped.
  • @param position Position of the item that has changed
  • @param payload Optional parameter, use null to identify a “full” update
  • @see #notifyItemRangeChanged(int, int)
    */
    public final void notifyItemChanged(int position, Object payload) {
    mObservable.notifyItemRangeChanged(position, 1, payload);
    }

在这里我们看到一句话:

@param payload Optional parameter, use null to identify a “full” update

传入“null”就是更新全部!那我们调用的时候是传入什么呢!看下:

public final void notifyItemChanged(int position) {
mObservable.notifyItemRangeChanged(position, 1);
}

继而调用:

public void notifyItemRangeChanged(int positionStart, int itemCount) {
notifyItemRangeChanged(positionStart, itemCount, null);
}

继而调用:

public void notifyItemRangeChanged(int positionStart, int itemCount, Object payload) {
// since onItemRangeChanged() is implemented by the app, it could do anything, including
// removing itself from {@link mObservers} - and that could cause problems if
// an iterator is used on the ArrayList {@link mObservers}.
// to avoid such problems, just march thru the list in the reverse order.
for (int i = mObservers.size() - 1; i >= 0; i–) {
mObservers.get(i).onItemRangeChanged(positionStart, itemCount, payload);
}
}

[捂脸] 一个大写的null…

OK,那我们修改下我们的调用方法:

/**

  • 暴露用于修改进度值的方法
  • @param progress
  • @param position
  • @param progressStr
    */
    public void setProgress(int progress, int position, String progressStr) {
    data.get(position).setProgress(progress);
    data.get(position).setDownloadPerSize(progressStr);
    notifyItemChanged(position, 1);
    }

/**

  • 暴露用于修改按钮文字值的方法
  • @param position
  • @param buttonStr
    */
    public void setButtonStatus(int position, String buttonStr) {
    data.get(position).setDownloadPerSize(buttonStr);
    notifyItemChanged(position, 1);
    }

这里我们传入了一个 “1”,这个1是随意传入的,其他值也可以。

继而我们需要重写onBindViewHolder方法如下:

@Override
public void onBindViewHolder(TestDownLoadHolder holder, int position, List payloads) {
XLog.e(“--------------------------has payloads”);
if (payloads.isEmpty()) {
XLog.e(“--------------------------no payloads”);
onBindViewHolder(holder, position);
} else {
XLog.e(“--------------------------false payloads”);
final AppInfoBean appInfoBean = data.get(position);
if (appInfoBean != null) {
holder.mPbDownProgress.setProgress(appInfoBean.getProgress());

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
img

分享读者

作者2013年java转到Android开发,在小厂待过,也去过华为,OPPO等大厂待过,18年四月份进了阿里一直到现在。

被人面试过,也面试过很多人。深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长,而且极易碰到天花板技术停滞不前!

我们整理了一份阿里P7级别的Android架构师全套学习资料,特别适合有3-5年以上经验的小伙伴深入学习提升。

主要包括腾讯,以及字节跳动,阿里,华为,小米,等一线互联网公司主流架构技术。如果你有需要,尽管拿走好了。

腾讯T3架构师学习专题资料

如果你觉得自己学习效率低,缺乏正确的指导,可以点击加入资源丰富,学习氛围浓厚的技术圈一起学习交流吧

群内有许多来自一线的技术大牛,也有在小厂或外包公司奋斗的码农,我们致力打造一个平等,高质量的Android交流圈子,不一定能短期就让每个人的技术突飞猛进,但从长远来说,眼光,格局,长远发展的方向才是最重要的。

35岁中年危机大多是因为被短期的利益牵着走,过早压榨掉了价值,如果能一开始就树立一个正确的长远的职业规划。35岁后的你只会比周围的人更值钱。

富,学习氛围浓厚的技术圈一起学习交流吧](https://bbs.csdn.net/topics/618156601)!**

群内有许多来自一线的技术大牛,也有在小厂或外包公司奋斗的码农,我们致力打造一个平等,高质量的Android交流圈子,不一定能短期就让每个人的技术突飞猛进,但从长远来说,眼光,格局,长远发展的方向才是最重要的。

35岁中年危机大多是因为被短期的利益牵着走,过早压榨掉了价值,如果能一开始就树立一个正确的长远的职业规划。35岁后的你只会比周围的人更值钱。

  • 19
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RecyclerView局部刷新闪烁是指在使用RecyclerView进行局部刷新时,界面出现明显的闪烁现象。这种现象通常是由于RecyclerView的Item刷新过程中引起的,下面是一些可能导致RecyclerView局部刷新闪烁的原因和解决方法。 1. 数据源变化频繁:当RecyclerView的数据源频繁发生变化时,局部刷新可能会导致闪烁。解决办法可以是尽量减少数据源的变化,例如使用DiffUtil工具类来优化数据比较,只更新真正变化的Item。 2. ViewHolder的重用问题:如果RecyclerView的Item中使用了动画效果,而在进行局部刷新时未正确处理ViewHolder的重用问题,可能会导致动画重复播放,从而产生闪烁。解决办法是在局部刷新的时候,清除或暂停动画效果,并正确处理ViewHolder的重用逻辑。 3. 刷新时的绘制问题:默认情况下,RecyclerView进行Item的局部刷新时,会重新绘制整个Item View,这可能会导致闪烁。解决办法是通过重写Item View的onDraw()方法,在局部刷新时只绘制变化的部分,而不是整个Item View。 4. 使用过多的动画效果:如果RecyclerView中的Item View使用了过多的动画效果,例如淡入淡出、旋转等,这些动画效果在局部刷新时会导致闪烁。解决办法是优化动画效果的使用,尽量减少动画效果的数量和复杂度。 总之,解决RecyclerView局部刷新闪烁问题的方法包括优化数据源的变化、正确处理ViewHolder的重用逻辑、优化绘制和动画效果的使用等。通过这些措施,可以有效减少RecyclerView局部刷新闪烁的现象,提升用户体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值