Fragment为什么需要一个默认的空的构造器

当系统因内存不足回收后台app时,用户切换回app,系统会通过onSaveInstanceState()和onRestoreInstanceState()恢复界面状态。对于使用FragmentState管理的Fragment,系统会通过反射调用Fragment的无参构造器实例化并恢复之前的状态。因此,Fragment需要一个公共的空构造器以确保在内存回收后能正确恢复。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一般情况下,没有这个空构造器也不会出什么大问题。但是当系统内存不足的情况下,app处于后台条件下,内存会被系统回收,这时用户将app切换到前台,系统会重新将之前回收的内容实例化回来。
这个过程是Android系统通过两个方法来实现的:
onSaveInstantceState();
onRestoreInstantceState();
第一个方法是系统要回收该界面(Activity、Fragment)时调用的方法,用于保存该(Activity、Fragment)的实例变量到外存。
第二个方法是系统恢复该(Activity、Fragment)时调用的方法,用于恢复之前被回收的(Activity、Fragment)实例。
好了系统UI的策略基本搞清楚了,现在解释为什么Fragment需要这么一个空构造器。
当app回到前台时,系统会调用Activity 的 onRestoreInstantceState();
Activity在实例化得时候,如果Activity是通过FragmentState来管理Fragment的,如果发现其中有Fragment,就会调用FragmentState的instantiate(),该方法的实现如下:

public Fragment instantiate(FragmentHostCallback host, Fragment parent) {
        if (mInstance != null) {
            return mInstance;
        }

        final Context context = host.getContext();
        if (mArguments != null) {
            mArguments.setClassLoader(context.getClassLoader());
        }

        mInstance = Fragment.instantiate(context, mClassName, mArguments);

        if (mSavedFragmentState != null) {
            mSavedFragmentState.setClassLoader(context.getClassLoader());
            mInstance.mSavedFragmentState = mSavedFragmentState;
        }
        mInstance.setIndex(mIndex, parent);
        mInstance.mFromLayout = mFromLayout;
        mInstance.mRestored = true;
        mInstance.mFragmentId = mFragmentId;
        mInstance.mContainerId = mContainerId;
        mInstance.mTag = mTag;
        mInstance.mRetainInstance = mRetainInstance;
        mInstance.mDetached = mDetached;
        mInstance.mFragmentManager = host.mFragmentManager;

        if (FragmentManagerImpl.DEBUG) Log.v(FragmentManagerImpl.TAG,
                "Instantiated fragment " + mInstance);

        return mInstance;
    }

好,追踪Fragment的instantiate方法:

public static Fragment instantiate(Context context, String fname, @Nullable Bundle args) {
        try {
            Class<?> clazz = sClassMap.get(fname);
            if (clazz == null) {
                // Class not found in the cache, see if it's real, and try to add it
                clazz = context.getClassLoader().loadClass(fname);
                sClassMap.put(fname, clazz);
            }
            Fragment f = (Fragment)clazz.newInstance();
            if (args != null) {
                args.setClassLoader(f.getClass().getClassLoader());
                f.mArguments = args;
            }
            return f;
        } catch (ClassNotFoundException e) {
            throw new InstantiationException("Unable to instantiate fragment " + fname
                    + ": make sure class name exists, is public, and has an"
                    + " empty constructor that is public", e);
        } catch (java.lang.InstantiationException e) {
            throw new InstantiationException("Unable to instantiate fragment " + fname
                    + ": make sure class name exists, is public, and has an"
                    + " empty constructor that is public", e);
        } catch (IllegalAccessException e) {
            throw new InstantiationException("Unable to instantiate fragment " + fname
                    + ": make sure class name exists, is public, and has an"
                    + " empty constructor that is public", e);
        }
    }

看到没最终调用该Fragment的Class类的newInstance方法,无参构造器。如果有要恢复的参数,会再次赋给mArguments。这点很重要,我之前一直在纠结如果有个无参构造器,那参数初始化的问题咋办。其实这个无参构造器系统只是用它来实例化而已!


总结:当系统因为内存紧张杀死非前台进程(并非真正的杀死),然后我们将系统杀掉的非前台app带回前台,如果有Fragment,那么会因为restore造成Fragment需要通过反射实例对象,从而将之前save状态还原,而这个时候需要Fragment有public的空构造器。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值