Fragment配合ViewPager时的OnResume调用时机的精准控制

场景:

  • 在最近的项目中有用到这样的一个常见的使用场景:Activity内包含一个ViewPager,里面装了几个Fragment,进行切换.在第三个ViewPager中,又做了一个postDelayed(Runable)实现自动轮播的轮播图.
  • 我想完成这样的一个需求:在第三个Fragment展现在眼前的时候开始自动轮播,一旦切换到别的Activity或者Fragment的时候停止轮播任务.还是可以节省一点资源的嘛.

尝试:

  • 开始我就在第三个Fragment里面写上:

    @Override
    public void onResume() {
        super.onResume();
        Log.i(TAG, "onResume: ");
        if (asv !=null) {
            asv.startAutoScroll();//开始轮播
        }
    }
    
    @Override
    public void onPause() {
        super.onPause();
        Log.i(TAG, "onPause: ");
        if (asv !=null) {
            asv.stopAutoScroll();//结束轮播
        }
    }
    

    可是忘记了,Fragment在这里的生命周期调用并非是我跳转到这个Fragment时调用onResume,我离开时调用onPause.结果当然是不能完美的开始,结束自动轮播了.

  • 要解决这个问题先来复习一下在这种情况下,Activity和Fragment的生命周期调用顺序: 
    这里写图片描述 
    刚刚进入Activity并没有切换到第三个Fragment但是它的生命周期已经走完了创建的过程,在Activity的onResume调用后它就开始调用自己的生命周期方法.已经执行了onResume方法,当然这个时候,轮播图是还没有获取到数据,准备好的,自然不能开始自动轮播,想要切换到第三个Fragment的时候才调用它的onResume是自以为是的.而且在手动切换到第三个Fragment的时候并没有调用它的常用生命周期方法,停止轮播当然也不用想了.(非常用的不了解).

    顺便贴一下现在按back销毁Activity的生命周期:

    这里写图片描述 
    在这个Activity销毁的时候才调用了Fragment销毁的生命周期.

  • 后面百度到说可以调用void setUserVisibleHint(boolean isVisibleToUser)方法,根据isVisibleToUser的状态来判断当前Fragment是否正显示在用户面前,起先我了解了一下他的调用顺序,竟然是在Fragment创建完成之前就会调用的,没有注意到他后面的调用时机.便没有尝试,而是采用监听ViewPager的onPageSelected方法来手动调用第三个Fragment的onResume方法来开始轮播,在跳转到其他Activity的时候系统调用第三个Fragment的onPause停止轮播,虽然有一些效果,但是感觉不完美.

解决:

  • 后来还是尝试了一下setUserVisibleHint这个方法,发现他的调用顺序如下: 
    这里写图片描述 
    在首次调用时,虽然Fragment都还没有创建完成,但是isVisibleToUser是false,手动切换进入的时候是true,手动切换到别的Fragment的时候也进行了调用flase.如下使用就能够在切换到这个Fragment的时候开始轮播,切出去的时候停止轮播了:

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (asv == null) {
            return;
        }
        if (isVisibleToUser) {
            asv.startAutoScroll();
        } else {
            asv.stopAutoScroll();
        }
    }
    
  • 你以为这样就完了么?开始我也这么以为,但是这样做还是存在一些问题:从这个Fragment进入别的Activity的时候轮播并没有停止,一直继续着,postDelayed一直都在循环的发送.这是我不能接受的.就在不爽之间,忽然灵机一动.我又添了几行代码,变成了下面这样:

     private boolean mIsVisibleToUser = false;
    
    //1.在别的Fragment的时候mIsVisibleToUser肯定是false,不会调用开始轮播
    //2.在当然Fragment的时候mIsVisibleToUser肯定是true,所有我从这个Fragment
    //  进入别的Activity又退来的时候,就会开始轮播
    //3.从别的Fragment进入Activity再回来的时候触发onResume也会开始轮播,因为
    //  mIsVisibleToUser在切换到别的Fragment的时候就已经被置为false了
    
    @Override
    public void onResume() {
        super.onResume();
        if (asv !=null&&mIsVisibleToUser) {//在这里进行一下判断
            asv.startAutoScroll();
        }
    }
    
    @Override
    public void onPause() {
        super.onPause();
        if (asv !=null) {
            asv.stopAutoScroll();
        }
    }
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
    
        mIsVisibleToUser = isVisibleToUser;//被调用时记录下状态
        if (asv == null) {
            return;
        }
        if (isVisibleToUser) {
            asv.startAutoScroll();
        } else {
            asv.stopAutoScroll();
        }
    }
    

    经过测试,感觉上完美的解决了这个问题,做下笔记,以后有没有不要太想当然,有线索就去尝试,实践是检验真理的唯一标准嘛.

猜你喜欢

转载自blog.csdn.net/hdhhd/article/details/81202135