RecyclerView Adapter 调用 notifyDataSetChanged后执行流程
因为遇到了一个问题调用notifyDataSetChanged不刷新界面,但是滑动一下屏幕,界面就刷新了。
在网上找了很久也没有解决。所以,自己追下流程看下,当我们调用notifyDataSetChanged时,它是怎么更新数据和刷新界面的呢?
先说下我在网上找到的解决方案吧
1)notifyDataSetChanged不是在主线程中执行的;
2)更新数据源时,更新的不是Adapter绑定的数据源。
好了,进入正题,来看下RecyclerView Adapter 的notifyDataSetChanged是怎么执行的吧
我们来看下Adapter的notifyDataSetChanged 方法
可以看到它调用的mObservable的notifyChanged(),mObservable是什么东西?它的定义如下,命名看起来跟观察者模式有关
继续看,在这里注册了一个观察者
可以确定是观察者模式了,观察者来自这里
继续看,notifyChanged后发生了啥
调用了观察者的onChanged方法,我们来看RecyclerViewDataObserver的onChanged方法
我们可以看到首先调用了
第一行,检查RecyclerView是否在正在计算布局或滚动,是就并抛出一个IllegalStateException
第二行,设置了一个状态,告诉recycleView数据集已改变。官方介绍是:
自上次调用onLayoutChildren以来数据集的结构是否已更改
第三行,processDataSetCompletelyChanged(true);,
官方解释:
据我们所知,处理的数据集已完全更改。一旦布局发生,所有附加项目都应丢弃或动画化。附加项目被标记为无效。因为仍可能在“数据集”之间预取项目 完全更改”事件和布局事件,所有缓存的项目都将被丢弃。
我的理解是,在通知RecyclerView数据集更改了,在布局更新之后丢弃掉之前的数据集。
看1.2两行,设置了标识位;
第三行,调用如下函数:
这个方法是:
将所有已知的视图标记为无效。 用于回应“整个世界可能已经改变”数据更改事件。
继续下去也是在通知视图无效和数据集改变。
我们继续回到onChanged方法:
进行这个mAdapterHelper.hasPendingUpdates()函数的判断,再调用requestLayout()进行界面刷新。
看到这里,我怀疑他是mAdapterHelper.hasPendingUpdates()为true,没有进行requestLayout().
我们去看hasPendingUpdates
boolean hasPendingUpdates() {
return mPendingUpdates.size() > 0;
}
//mPendingUpdates 定义
final ArrayList<UpdateOp> mPendingUpdates = new ArrayList<UpdateOp>();
可以看到返回的是false,是会进入的requstLayout的。所以这里是没有问题的,继续往下走发现会回到断点位置notifyDataSetChanged。然后,会进入View,但是就没法走了,不是走到的正常的代码。
大概可能是看出来requstLayout并不是立即就会更新代码,而是要过一段时间才会更新。
但是,为什么过了一段时间却没有更新,得滚动一下它才会更新呢?
目前没有找到原因,不行就只能让他滚一个像素更新了。
总结:
问题没解决,倒是知道了RecyclerView,是怎么更新界面的。观察者模式在Android中真是无处不在啊。
PS:
以下几个方法,是类似的,都是通过观察者模式调用到RecyclerViewDataObserver 里面相应的change方法进行界面刷新
* @see #notifyItemChanged(int)
* @see #notifyItemInserted(int)
* @see #notifyItemRemoved(int)
* @see #notifyItemRangeChanged(int, int)
* @see #notifyItemRangeInserted(int, int)
* @see #notifyItemRangeRemoved(int, int)
PS1:我来解决方法啦:
(先说下大概的背景,我的页面上方有一个网络播放器(WebView),下方是一个播放列表(RecyclerView ),中间是正在播放的视频信息)
而我要做的是当我点击RecyclerView中的条目时,播放它并改变条目颜色,表明当前条目正在播放
而问题是,我点击了之后,会播放相应条目,但条目颜色不更新。
我们开始一直以为是RecyclerView的更新问题,还特地看了源码,追了界面更新流程,都没有什么问题,但就是不刷新界面。
在同事的指导下,发现将显示视频播放时间的Chronometer去掉后,能正常更新,虽然不知道为啥,但是,总算能行了吧?
然后,现实并非如此。不播放的时候是正常,但一开始播放视频就出问题。
在经过我的不断尝试之后,总算是发现了问题,只要网络播放器通过JavaScript调用了activity中的回调,并且更新了activity的界面,就不能刷新RecyclerView的条目了。
想不明白为啥,然后,突然想到在activity中的回调更新界面时,加入了runOnUiThread包裹。如下,
//回调函数
//...
runOnUiThread(new Runnable() {
@Override
public void run() {
//ui更新
}
});
//...后续操作
然后,完美解决。
打了回调函数的线程是在JavaBridge。
大致查了下资料,JavaBridge是跟
不加runOnUiThread他也是可以正常UI更新的,但是,就是影响到了RecyclerView的更新,实在不明白,但是,困扰好几天的问题好歹解决了。
今天的文章浅析notifyDataSetChanged执行流程+一个界面不刷新问题解决分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/24096.html