看这篇文章前,大家应该先对setMaxLifecycle有所了解。
上年年末,谷歌为新版本的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下载这个库,并导入到你的项目中我相信有点经验的开发人员都知道怎么import module。
2、从我fork的https://github.com/Ubitar/Fragmentation的fragmentation_core库中找到下方这3个文件:VisibleDelegate、SupportFragmentDelegate,以及BaseSupportFragment文件,并覆盖你项目中对应的文件。当时的Fragmentation 的版本是 androidx 1.0.5
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。
大哥,觉得可以的话Gayhub给个Star吧,他们是有交互效果的啊