简介
在实际开发过程中,使用到ViewPager
+Fragment
的方式进行显示布局。由于存在需求缓存已加载的Fragment
,故自定义了FragmentAdapter
,不destoryItem
,仅仅注释了destroyItem
方法里的操作,代码NoDestroyItemFragmentAdapter。
至于为什么不设置ViewPager.setOffscreenPageLimit(int limit))方法,是由于如果设置了此方法,会导致所有的页面同时加载,增加了缓存布局数量。
BUG
描述
此时,导致了一个问题:当有非当前展示的页面需要刷新时,调用的requestLayout()
无法执行到onLayout()
方法。对应项目中的现象就是:调用notifyDataChanged()
无法刷新列表。
解决
在Fragment
的setMenuVisibility
中调用一次requestLayout()
。保证当前View的PFLAG_FORCE_LAYOUT
被消费掉。
|
分析
查看RecyclerView源码,查看RecyclerViewDataObserver
的onChanged
方法
|
继续查看requestLayout()
和onLayout()
方法;
|
其中dispatchLayout()
即为RecyclerView
页面布局。
查看View.requestLayout()
方法
|
当断点到mParent.isLayoutRequested()
时发现,此时其mParent
的mPrivateFlags
存在标志位PFLAG_FORCE_LAYOUT
即mParent.isLayoutRequested()
返回的是true
而对于标志位PFLAG_FORCE_LAYOUT
是在forceLayout()
和requestLayout()
时设置,layout结束时清空:
public void layout(int l, int t, int r, int b) { |
此时,想到会不会是因为布局的父类只被requestLayout()而没有执行layout方法。对应的父类就是ViewPager,此时查看ViewPager的onLayout方法:
|
在上面的判断中会判断是否存在ViewPager
缓存的列表中,而这个列表维护是在起当有元素新增时添加,当元素移除时删除。坑就在这里。
在当前项目,由于没有设置默认绘制的数量,使用了其默认数量即当前+1+1(一前一后),此时如果当切换的Item超过了这个数量,布局的里面的列表item就不会包括切换前的那个布局,就导致切换前的那个布局无法layout()
。从而导致了后面的一系列问题(子View的requestLayout()
无法响应)。
总结
- 当自定义了如下adapter之后,可通过再次调用
requestLayout()
来解决 - 可通过
ViewPager
的ViewPager.setOffscreenPageLimit(int limit)
进行控制
代码区
NoDestroyItemFragmentAdapter
|