美文网首页
AndroidX对ViewPager懒加载的影响及解决方案

AndroidX对ViewPager懒加载的影响及解决方案

作者: dasamanren | 来源:发表于2019-11-06 17:54 被阅读0次

    本文主要是讲解迁移到AndroidX之后,对原本的ViewPager懒加载造成的影响,和如何进行优化。参考的项目来自

    波澜步惊 的文章 《手把手讲解 ViewPager懒加载》

    最后的代码修改对比也是来自大神的文章,建议先看一下再过来看本文

    一、为什么要迁移为AndroidX

    根据官方说明,AndroidX是对原始Android支持库(android.support.*)进行了重大改进和统一管理,旧的库依然能用,但是新库的开发都将会在AndroidX中进行,所以建议还是迁移到AndroidX。

    image-20191106141427918.png

    具体如何迁移,本文在此不做详细说明,请查看官方文档

    二、迁移之后的区别

    迁移之后出现问题,主要是因为FragmentPagerAdapter的文件有所改动

    1 初始化

    旧版:

    image-20191106143344778.png

    新版:


    image-20191106143525127.png

    可以看到初始化的方式添加了一个@Deprecated (废弃)的注解,就是告诉大家不要用这种方式进行初始化了。那么应该怎么进行初始化呢?

    image-20191106144016864.png

    这里就可以看到,初始化的时候,除了需要传入fm,同时还需要传一个behavior,让我们来看看Behavior具体是哪些值?

    image-20191106144411441.png

    根据注释可以知道

    当behavior == BEHAVIOR_SET_USER_VISIBLE_HINT 时,Fragment切换时,会触发setUserVisibleHint。
    这个效果和\color{#00ffff}{旧版}的效果一样,也就是说,如果你不想修改原来懒加载的逻辑,只需要这么写

    FragmentPagerAdapter adapter = new FragmentPagerAdapter(fm);
    或者
    FragmentPagerAdapter adapter = new FragmentPagerAdapter(fm, BEHAVIOR_SET_USER_VISIBLE_HINT);
    

    但是,我们看到了BEHAVIOR_SET_USER_VISIBLE_HINT也被标识了@Deprecated (废弃),建议我们使用BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT。所以\color{#00ffff}{新版本}初始化方式是:

    FragmentPagerAdapter adapter = new FragmentPagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
    

    而这时候会用到生命周期状态标识Lifecycle.State。

    2 FragmentPageAdapter初始化Fragment

    @NonNull
        @Override
        public Object instantiateItem(@NonNull ViewGroup container, int position) {
            //...省略非重点代码 
            if (mBehavior == BEHAVIOR_SET_USER_VISIBLE_HINT) {
                //旧版本,触发setUserVisibleHint
                fragment.setUserVisibleHint(false);
            }
    
            mFragments.set(position, fragment);
            //关键句,添加Fragment进入事物list
            mCurTransaction.add(container.getId(), fragment);
    
            if (mBehavior == BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
                //AndroidX,设置初始化执行到onStart()就停止了
                mCurTransaction.setMaxLifecycle(fragment, Lifecycle.State.STARTED);
            }
    
            return fragment;
        }
    

    追踪进入mCurTransaction.add(container.getId(), fragment);方法

    image-20191106161227079.png
     void doAddOp(int containerViewId, Fragment fragment, @Nullable String tag, int opcmd) {
        //...省略非重点代码
         addOp(new Op(opcmd, fragment));
     }
    
    image-20191106161358476.png

    添加的是一个Op对象,看看Op是如何初始化的。

    Op(int cmd, Fragment fragment) {
                this.mCmd = cmd;
                this.mFragment = fragment;
                //初始化执行到onResume()
                this.mOldMaxState = Lifecycle.State.RESUMED;
                this.mCurrentMaxState = Lifecycle.State.RESUMED;
            }
    

    到这里,我们就能明白了如果是旧版本,Fragment初始化的时候,默认会执行到onResume(),而AndroidX只会执行到onStart(),所以我们迁移到AndroidX之后,不需要全都依靠setUserVisibleHint()来判断当前页面是否显示,我们可以根据onResume()来判断。

    3 迁移到AndroidX之后,BaseFragment相应的修改

    @Nullable
        @Override
        public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
            mRoot = inflater.inflate(getLayoutId(), container, false);
            Log.d(getLifeCycleTag(), "onCreateView");
            initView(mRoot);
            //在View创建完毕之后,isViewCreate 要变为true
            isViewCreated = true;
            //下面2段代码可以删除
            //if (!isHidden() && getUserVisibleHint())
                //dispatchVisibleState(true);
            return mRoot;
        }
    
    @Override
        public void onResume() {
            super.onResume();
            Log.d(getLifeCycleTag(), "onResume");
           /* 旧版本
            if (!isFirstVisible) {
                if (!isHidden() && !currentVisibleState && getUserVisibleHint())
                    dispatchVisibleState(true);
            }
            */
            //新版本
            if (!isHidden() && !currentVisibleState && isResumed()) {
                dispatchVisibleState(true);
            }
        }
    
    @Override
        public void onPause() {
            MobclickAgent.onPageEnd(this.getClass().getName());
            super.onPause();
            Log.d(tag,"onPause: ");
            /* 旧版本
            if (currentVisibleState && !isResumed()) {
                dispatchVisibleState(false);
            }
            */
            //新版本
            if (currentVisibleState && !isResumed()) {
                dispatchVisibleState(false);
            }
        }
    //其他不需要更改
    

    三、总结

    迁移到AndroidX,主要改变的是FragmentPagerAdapter对Fragment的初始化方式进行了优化,所以才需要进行这样修改,其实问题不难,顺着逻辑看一下源码就能发现区别啦。希望对大家有所帮助,如果文章有不足之处,请不吝指出,谢谢。

    四、鸣谢

    感谢 波澜步惊 的文章 《手把手讲解 ViewPager懒加载》ViewPager懒加载写得很详细,易懂。

    感谢 享学课堂 avlin老师 提供的demo 以及视频

    相关文章

      网友评论

          本文标题:AndroidX对ViewPager懒加载的影响及解决方案

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