美文网首页Android知识梳理Android
为什么要用newInstance来实例化Fragment?

为什么要用newInstance来实例化Fragment?

作者: andev009 | 来源:发表于2020-01-08 14:43 被阅读0次

    看了些文章,感觉讲的有疑问,看源码研究了下。先说结论,Android 在恢复Fragment时,调用的是无参的构造函数,如果使用new的方式构造Fragment,Fragment重新构建会丢失状态。使用newInstance方式会将参数存储在mArguments中,在Fragment恢复时,会从mArguments中取得参数恢复状态。
    过程分两步:Fragment销毁和Fragment恢复。
    1、Fragment销毁
    在屏幕旋转等状态下,FragmentActivity会调用onSaveInstanceState方法:

    protected void onSaveInstanceState(Bundle outState) {
            super.onSaveInstanceState(outState);
            this.markFragmentsCreated();
            //取得Fragment相关的参数
            Parcelable p = this.mFragments.saveAllState();
            if (p != null) {
                //参数存Bundle,与之对应,之后在FragmentActivity的onCreate里取得Bundle
                outState.putParcelable("android:support:fragments", p);
            }
             ...................
    }
    

    接着看看mFragments.saveAllState(),通过FragmentController中转了下,最后调用FragmentManager的saveAllState方法:

    //忽略不相关代码,只看参数保存部分
    Parcelable saveAllState() {
        //N代表Fragment的个数
        FragmentState[] active = new FragmentState[N];
        //取得Fragment对象,i是遍历列表的索引
         Fragment f = (Fragment)this.mActive.valueAt(i);
        //重点在这里,将该Fragment的mArguments赋值给新建的
        //FragmentState对象,new FragmentState只是简单的数据copy
         FragmentState fs = new FragmentState(f);
         active[i] = fs;
        //构建FragmentManagerState类型的对象fms,mActive参数赋值为
        //FragmentState,这样fms将会有Fragment的mArguments参数。
         FragmentManagerState fms = new FragmentManagerState();
         fms.mActive = active;
         return fms;
    }
    

    总结上面,就是在FragmentActivity销毁前,调用onSaveInstanceState方法,里面遍历包含的Fragment,将Fragment的mArguments一层层封装,最后保存在outState的Bundle对象里用于Fragment恢复使用。
    2、Fragment恢复
    首先FragmentActivity的调用生命周期方法:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          if (savedInstanceState != null) {
               //取得之前销毁时调用onSaveInstanceState保存的Bundle
                Parcelable p =savedInstanceState.getParcelable("android:support:fragments");
     //恢复Fragment状态
     this.mFragments.restoreAllState(p, nc != null ? nc.fragments : null);
        }
    }
    

    同样通过FragmentController中转了下,最后调用FragmentManager的restoreAllState方法:

        void restoreAllState(Parcelable state, FragmentManagerNonConfig nonConfig) {
         //将state转化成之前保存mArguments的类型FragmentManagerState
         FragmentManagerState fms = (FragmentManagerState)state;
        //很熟悉了,fs里面有mArguments
         FragmentState fs = fms.mActive[index];
    //构建Fragment
     Fragment f = fs.instantiate(this.mHost, this.mContainer, this.mParent, childNonConfig, viewModelStore);
    }
    

    看看fs.instantiate做了什么:

    public Fragment instantiate(FragmentHostCallback host, FragmentContainer container, Fragment parent, FragmentManagerNonConfig childNonConfig, ViewModelStore viewModelStore) {
    //mInstance就是Fragment对象,mArguments就是之前保存的参数
    this.mInstance = Fragment.instantiate(context, this.mClassName, this.mArguments);
    }
    

    终于到了最后一步了,Fragment对象的类名知道,mArguments也知道了,可以创建对象,并恢复参数了,看看Fragment.instantiate:

    public static Fragment instantiate(Context context, String fname, @Nullable Bundle args) {
            try {
                Class<?> clazz = (Class)sClassMap.get(fname);
                if (clazz == null) {
                    clazz = context.getClassLoader().loadClass(fname);
                    sClassMap.put(fname, clazz);
                }
    
                Fragment f = (Fragment)clazz.getConstructor().newInstance();
                //恢复参数的位置在这里
                if (args != null) {
                    args.setClassLoader(f.getClass().getClassLoader());
                    f.setArguments(args);
                }
    
                return f;
            } catch (ClassNotFoundException var5) {
                throw new Fragment.InstantiationException("Unable to instantiate fragment " + fname + ": make sure class name exists, is public, and has an" + " empty constructor that is public", var5);
            } catch (java.lang.InstantiationException var6) {
                throw new Fragment.InstantiationException("Unable to instantiate fragment " + fname + ": make sure class name exists, is public, and has an" + " empty constructor that is public", var6);
            } catch (IllegalAccessException var7) {
                throw new Fragment.InstantiationException("Unable to instantiate fragment " + fname + ": make sure class name exists, is public, and has an" + " empty constructor that is public", var7);
            } catch (NoSuchMethodException var8) {
                throw new Fragment.InstantiationException("Unable to instantiate fragment " + fname + ": could not find Fragment constructor", var8);
            } catch (InvocationTargetException var9) {
                throw new Fragment.InstantiationException("Unable to instantiate fragment " + fname + ": calling Fragment constructor caused an exception", var9);
            }
        }
    
    

    可以看到,反射调用构建出Fragment后,在通过setArguments恢复参数。

    相关文章

      网友评论

        本文标题:为什么要用newInstance来实例化Fragment?

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