看这篇文章前,大家应该先对setMaxLifecycle有所了解。
本文基于 https://github.com/JantHsueh/Fragmentation 维护的1.0.5进行修改,1.0.6后续会补上
上年年末,谷歌为新版本的Fragment
添加了控制其在ViewPager
中的生命周期的新方式——setMaxLifecycle
(而ViewPager2
中默认且只有这个方式)。
听说后面还要把
onActivityCreated
砍了,注意下。setMaxLifecycle
的添加,简化了ViewPager
在切换对Fragment
可见性判断的复杂度,但是也增加了一些操X的问题:如果你使用了ViewPager
的setMaxLifecycle
。因为生命周期改变了,你的程序可能要做出相应的适配。
如果刚好你在用Fragmentation,又碰上了ViewPager
的setMaxLifecycle
,那么你就会发现只要打开了ViewPager所属的页面,ViewPager
容器内的所有Fragment
都会立刻调用了supportVisible()
可见可见函数,无论这些Fragment
是不是都显示了。当然,onLazyInitView
懒加载也被调用了。
目前我所知道有三种解决办法,分享下
1、找作者或者接手Fragmentation
项目的大佬解决这个问题。
2、自己动手丰衣足食
3、用回ViewPager
的BEHAVIOR_SET_USER_VISIBLE_HINT
方法这么多,足足有三个,我们来用下排除法找答案。
第一个呢,我也提了issue了,就看接手大佬能不能看到了。
第二个呢,需要自己download整个项目下来改,下文会讲
第三个呢,如果你用的ViewPager1
,这可能就是换个Adapter
或者改个参数的事,如果你用的是ViewPager2
,那你的工作量可能就有一点了,你自己掂量下,反正我是觉得ViewPager2
不错。
怎么改嘛
注意:这个修改,我会直接弃用onActivityCreated,而使用onStart和onResume来判断Fragment是否处于活跃或显示状态,即在onResume后再调用supportVisible,请注意检查你的项目中业务逻辑顺序是否有需要调整
1、从Fragmentation
下载这个库,并导入到你的项目中
2、从我fork的https://github.com/Ubitar/Fragmentation的fragmentation_core库中找到下方这3个文件:VisibleDelegate
、SupportFragmentDelegate
,以及BaseSupportFragment
文件,并覆盖你项目中对应的文件。
3、然后,没了,你们引用这个本地库测试下吧,不要忘记把旧的fragmentation_core
依赖去除
源码修改解析
分析内容
1、打开BaseSupportFragment
,可以看到里面几乎所有的方法都是通过SupportFragmentDelegate
代理的,有了解过Fragment
或者Activity
源码的人都知道这很Android。从SupportFragmentDelegate
源码中搜索onSupportVisible
函数,发现是空的。
BaseSupportFragment
再次搜索onSupportVisible
的引用,找到了调用其的VisibleDelegate
类2、在
VisibleDelegate
中顺着Fragment
的生命周期去找有关分发可见性或直接控制可见性的函数。首先onCreate
和onResume
方法是可以排除的,在剩下的其他函数onActivityCreated()中可以找到有一个关于控制可见性的函数,initVisible()
。3、调查下
initVisible()
isFragmentVisible()
很可疑,跟踪。
就那么一句话,是真正判断可见性的函数了。
那么我们写个ViewPager
运行下,调试看到fragment.getUserVisibleHint()
在使用setMaxLifecycle
的情况下无论如何都是true
,所以当ViewPager活跃时,上面所有Fragment都被认定为可见了,后面的onLazyInitView()
也自然被调用了。
4、但是,先别急着修改isFragmentVisible()
,由于使用了setMaxLifecycle
的缘故,需要把onActivityCreated()
中的内容迁移到onStart()
中,遗弃onActivityCreated()
BaseSupportFragment
和SupportFragmentDelegate
也要做出响应的修改,具体修改内容MySupportFragment、SupportFragmentDelegate ,注意,多了个 onViewStateRestored()
5、现在回头改
isFragmentVisible()
,既然setMaxLifecycle
是通过onResume
来通知可见性的,那这里就是缺少了一个fragment.isResumed()
。isResumed()
都是管用的例如这里的isResumed()
恒定是false
的isFragmentVisible
分为isFragmentVisibleOnResume()
和isFragmentVisibleOnPause()
isFragmentVisible()
补充:
可能我的描述不够直观,https://github.com/Ubitar/Fragmentation 还是show me the code 最好,我没有改Fragmentation
的demo,仅仅修改了其core
疑问
1、怎么没有兼容setUserVisibleHint
版本,直接跳setMaxLifecycle
了?
额。我没有写,这个需要你看懂setMaxLifecycle
的兼容后,再回去把旧的代码还原回来(onActivityCreated
和isFragmentVisible
之类),通过自己设置的Boolean
值来控制是否兼容setMaxLifecycle
。