美文网首页程序人生
在使用Fragment过程中遇到的坑(一)切换判断界面是否可见,

在使用Fragment过程中遇到的坑(一)切换判断界面是否可见,

作者: 暮色将蓝 | 来源:发表于2018-07-12 14:29 被阅读0次

    背景:项目中每个页面多个地方使用到Fragment,有的是在viewpager中,有的自己进行管理;项目运行一段时间后想对fragment进行懒加载处理,很早之前只对ViewPager中的Fragment进行过处理,结果在处理过程中遇到的一些问题。

    先看一段代码

    public abstract class BaseFragment extends Fragment {
    
        private boolean isFirstVisible = true;
        private boolean isFirstInvisible = true;
    
        private boolean isViewCreated;
        private boolean isUIVisible;
    
        @Override
        public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
            super.onViewCreated(view, savedInstanceState);
            isViewCreated = true;
            lazyLoad(); // 执行懒加载,因为无法确定setUserVisibleHint和onViewCreated哪个方法先执行,因此两个方法里面都需要调用lazyLoad
        }
    
        @Override
        public void setUserVisibleHint(boolean isVisibleToUser) {
            super.setUserVisibleHint(isVisibleToUser);
            if (isVisibleToUser) {
                isUIVisible = true; //当前fragment可见
                if (isFirstVisible) {
                    //如果是第一次可见,则进行懒加载
                    isFirstVisible = false;
                    lazyLoad();
                } else {
                    //不是第一次可见,则调用onUserVisible()
                    onUserVisible();
                }
            } else {
                isUIVisible = false;
                if (isFirstInvisible) {
                    isFirstInvisible = false;
                    //第一次不可见
                    onFirstUserInvisible();
                } else {
                    //非第一次不可见
                    onUserInvisible();
                }
            }
        }
    
        private void lazyLoad() {
            if (isViewCreated && isUIVisible) { //需要进行双重判断,避免因为setUserVisibleHint先于onViewCreaetd调用时,出现空指针
                LogUtils.e( this.getClass().getSimpleName()  + "lazyLoad");
    //            initViewsAndEvents();
                onFirstUserVisible();  //进行初次可见时的加载
            }else {
                LogUtils.e( this.getClass().getSimpleName()  + ">>>>isViewCreated:" + isViewCreated + "------>>>>>isUIVisible:" + isUIVisible);
            }
        }
    
        protected abstract void onFirstUserVisible();
    
        protected abstract void onUserVisible();
    
        protected abstract void onFirstUserInvisible();
    
        protected abstract void onUserInvisible();
    }
    

    一般ViewPager+Fragment的时候,主要使用到了setUserVisibleHint()方法进行判断Fragment是否可见,来进行懒加载处理。

    但是
    但是
    但是
    在某些场景中setUserVisibleHint()竟然没有执行~~~~:在未使用Viewpager,而是自己通过FragmentTransaction 对Fragment进行add hide show操作,setUserVisibleHint()方法没有被调用。原因是hide()和show()方法调用时,Fragment不走任何的生命周期。

    这时候突然发现另外一个Fragment方法onhiddenchanged(),该方法用于判断fragment显隐,正好切合hide show操作。

    public abstract class LazyFragment extends BaseFragment {
        public static final String TAG = LazyFragment.class.getSimpleName();
    
    
        private boolean hasLoaded = false;
    
        private boolean isCreated = false;
    
        private boolean isVisibleToUser = false;
        private View view;
    
        @Override
        protected void initViews(View view, @Nullable Bundle savedInstanceState) {
            isCreated = true;
            this.view = view;
            lazyLoad(this.view, savedInstanceState);
        }
    
        @Override
        public void setUserVisibleHint(boolean isVisibleToUser) {
            this.isVisibleToUser = isVisibleToUser;//注:关键步骤
            super.setUserVisibleHint(isVisibleToUser);
            lazyLoad(view, null);
        }
    
        private void lazyLoad(View view, Bundle savedInstanceState) {
            if (!isVisibleToUser || hasLoaded || !isCreated) {
                return;
            }
            lazyInitView(view, savedInstanceState);
            hasLoaded = true;//注:关键步骤,确保数据只加载一次
        }
    
        public abstract void lazyInitView(View view, Bundle savedInstanceState);
    
        @Override
        public void onDestroyView() {
            super.onDestroyView();
            isCreated = false;
            hasLoaded = false;
        }
    
    }
    

    然后对BaseFragment进行进一步封装,应对各种情况。

    总结

    onhiddenchanged()

    用FragmentTransaction来控制fragment的hide和show时,那么这个方法就会被调用。每当你对某个Fragment使用hide或者是show的时候,那么这个Fragment就会自动调用这个方法。

    (使用情况:你自己去管理Fragment,而不是用viewpager管理的时候)

    setUserVisibleHin()

    在使用viewpager的时候,viewpager内部有个提前缓存的机制(默认是提前缓存一页),比如你在看第一个Fragment的时候,隔壁的Fragment已经创建好了,但此时的状态却是不可见的。

    但是这时候Fragment不会去调用上面说的onhiddenchanged方法,只会调用setUserVisibleHint这个方法。

    参考

    fragment 切换判断界面是否可见 setUserVisibleHint和onHiddenChanged使用场景

    关于onhiddenchanged和setUserVisibleHint函数的知识

    支付宝发红包啦!即日起还有机会额外获得余额宝消费红包!长按复制此消息,打开最新版支付宝就能领取!q1iF0j95U0

    微信图片_20180712133728.png

    相关文章

      网友评论

        本文标题:在使用Fragment过程中遇到的坑(一)切换判断界面是否可见,

        本文链接:https://www.haomeiwen.com/subject/ldtrpftx.html