Fragment中有onResume()和onPause()方法,一般来说这两个方法是跟Activity绑定的,即触发Activity的这两个方法时就会触发Fragment的这两个方法,另外Fragment还有可见与不可见状态,但是Fragment中的onResume()/onPause()和可见/不可见完全是两码事。这里我将这两种情况做了一下分析,以做记录。
一、onResume()和onPause()
这两个方法会跟随Activity而变化,但是也不一定只有经历Activity的生命周期才会触发,这又分两种情况:
1. 在Activity中单独使用Fragment
单独使用Fragment的情况下,除了会跟随Activity的onResume和onPause的情况外,在当前Activity中添加一个Fragment时,被添加的Fragment都会调用onResume,这包括通过add和replace的方式添加;在Fragment销毁的情况下都会触发onPause,如果是add到回退栈的情况,back键就会触发onPause,如果是replace的情况,则被替换掉的Fragment会触发onPause。
如果Activity中添加了多个Fragment,那么当Activity触发onResume和onPause时,Activity中的每一个Fragment都会触发这两个方法,即便这个Fragment不在最顶层。
2. 在ViewPager中使用Fragment
在ViewPager中使用Fragment时这两个方法就更加奇妙了,因为你看不见的Fragment也会触发onResume和onPause,这时跟ViewPager预加载相关,默认情况下,ViewPager左右会预加载1页,所以如果ViewPager中有四个Fragment A、B、C、D,当你展示A Fragment的时候,A和B两个Fragment都会触发onResume,当你切换到B,则C Fragment触发onResume,当你再切换到C,则A Fragment会触发onPause(这时A已经销毁了),然后D Fragment会触发onResume,再回来的时候也是这样,如此反复。
即被ViewPager预加载的Fragment全部会调用onResume,被ViewPager销毁的Fragment全部会调用onPause。
当ViewPager所在的Activity触发onResume和onPause时,ViewPager中所有已创建的Fragment都会触发这两个方法(即包括ViewPager预加载的Fragment),比如假如你当前处于B Fragment, 当你按下Home键时,A B C三个Fragment都会触发onPause,当你再返回来的时候,A B C三个Fragment都会触发onResume。
二、Visible和Hidden
Fragment 中有两个方法isHidden()和isVisible(),注释说是可以用来判断其可见性,但是经过测试如果你是在Fragment的onResume/onPause方法中调用这两个方法判断是不准确的,onResume的方法中isVisible()有可能为false, 而onPause的方法中isVisible()也有可能为true。可见性需要通过下面两个方法做判断:
@Override
public void onHiddenChanged(boolean hidden) {
super.onHiddenChanged(hidden);
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
}
这也分两种情况,onHiddenChanged是在单独使用Fragment的时候进行show/hide操作时使用,setUserVisibleHint是在ViewPager中使用时判断。
1. 单独使用Fragment的情况
单独使用Fragment的情况比较简单,就是对Fragment进行show和hide的时候会回调onHiddenChanged方法。除此之外的操作,如add/replace/remove都不会触发这个方法。
2. 在ViewPager中使用Fragment的情况
在ViewPager中使用Fragment时,同样跟ViewPager的预加载有关,假如我们有A B C D四个Fragment,初次打开默认是A Fragment,这时会调用A和B的setUserVisibleHint方法设置参数值为false, 紧接着它会再调用一次A的setUserVisibleHint方法设置参数值为true。当切换到B时,则会调用C和A的setUserVisibleHint方法参设置数值为false,当切换到C时,则会调用D和B的setUserVisibleHint方法设置参数值为false,当再次返回B时,则会调用A和C的setUserVisibleHint方法设置参数值为false。
即被ViewPager预加载的Fragment全部会调用setUserVisibleHint方法设置参数值为false,只有当前展示的那一页则会调用setUserVisibleHint方法设置参数值为true。另外值得注意的一点是setUserVisibleHint这个方法的调用时机很早,会在Fragment的onAttach()、onCreate()等方法之前调用,所以,如果你在这里用到了全局变量一定要判断是否初始化了。
总结
以上是经过测试分析的结果,看了一些博客,有些人喜欢将onResume和可见状态联合起来做Fragment的可见性的判断,这个是非常麻烦并且十分不靠谱的,因为在Fragment的onResume/onPause的时候它的可见状态是完全不确定的。因此不能把onResume/onPause和visible/hidden状态混为一谈,要分开对待,因为这两种有可能会交叉发生。
总之,经过测试,要想十分准确的判断Fragment是否是对用户可见还是相当麻烦的,而在有些情况下根本无法判断。只能期望未来Google能给一个好的解决方案吧,目前能做的只有清楚在什么情况下会触发哪些方法才能正常处理你的业务逻辑。如果你有更好的理解欢迎留言评论。