You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
解决方案:ViewHolder views must not be attached when created. Ensure that you are not passing 'true' to the attachToRoot parameter of LayoutInflater.inflate(..., boolean attachToRoot)
#2796
Closed
limuyang2 opened this issue
Jun 28, 2019
· 3 comments
ViewHolder views must not be attached when created. Ensure that you are not passing 'true' to the attachToRoot parameter of LayoutInflater.inflate(..., boolean attachToRoot)
Describe the bug
BUG说明
在
viewPager2
(对于视图回收的viewPager
理应也会出现此bug)上,Fragement
里放垂直滑动的recyclerView,第一页
Fragement
里的RecyclerView adapte
设置了空布局后;滑动到第四页,此时,第一页的Fragement已经被回收,执行了onDestroy()
方法,但是,此Fragement
的实例还在。这时候再从第四页,滑动回到第一页,
Fragement
会重走onCreateView
和onViewCreated
,这时候,由于视图被重建,所以RecyclerView
并不相同,同时对RecyclerView
进行重新设置adapter
。(理想的、正确的状态是,从第四页回到第一页仍然显示空布局)
前面已经提到,
Fragement
只是回收视图,但是实例任然在,所以作为全局变量的adapter
并没变,adapter
仍是同一个,此时的问题就变成了:同一个
adapter
设置给了两个或者多个不同实例的RecyclerView
,这时候BUG出现,重复设置adapter
会报如下错:此错误非常不明确,没有错误具体行数,排查较为麻烦。
经过反复对源码的断点调试,以及对源码翻看,发现问题所在。
首先源码中的
mEmptyLayout
是一个class全局变量,当显示空布局时,在:此方法中,
mEmptyLayout
被直接进行了引用,在第一次给RecyclerView
设置adapter
的时候,没问题。当第二次把同一adapter
设置给不同实例的RecyclerView
后,就会出现上述错误。因为mEmptyLayout
被第一个RecyclerView
视图所持有,不能被添加到第二个RecyclerView
上。也就是说
adapter
不能被复用,所以在之前的Issuse
中,给出的解决方案都是让ViewPager
不回收视图,全部保存在内存中。其实说实话,这种方式对内存很不友好。解决方案:
很简单:将上述方法修为以下:
同时,为了保证复用性,以下方法最好也进行修改:
解释
解决方法是我们此小团队考虑到的最简方式,
第一、不论是对于
viewPager
还是viewPager2
,我们一致认为,不应该强行保存所有视图在内存中,当页数很多时候,同时每个页面也复杂的话,非常占用内存。第二、
viewPager
可以设置setOffscreenPageLimit
,用于达到缓存的目的,或者重写viewPager适配器中的destroyItem
。但是在
AndroidX
的viewPager2
中,虽然也有setOffscreenPageLimit
方法,但是其实际使用效果会有点区别。因为viewPager2
本身也是用RecyclerView
实现的,所以会遵循RecyclerView
的复用机制。具体可以去阅读源码,不再解释。第三、我们也想到过,每次重建视图,就重新new一个Adapter,但是此问题在于,Adapter除了data数据、空布局状态等等需要保存拷贝,还有很多内部状态需要保存拷贝。除非克隆一个
Adapter
,这是不现实的,唯有复用,并且RecyclerView Adapter
是一个松耦合设计,本身就应该具有复用特性,并且实际测试情况下来,重建的RecyclerView
视图在复用Adapter
后会自动恢复滚动状态等等,这一特性,已经说明了系统本身的设计用意。再者,每次对
Adapter
的重建,都是不必要的性能开销。我相信从
Google
的出发点,并不是希望我们什么东西都扔给内存,导致内存的滥用。测试使用的Fragment代码
其实就是非常常规的写法:
致谢
这是一个很优秀的开源库,感谢各位作者。希望大家都参与到项目的维护中,你为人人,人人为我。
The text was updated successfully, but these errors were encountered: