activity和fragment的参数传递(setArgment)

对于activity和fragment的参数传递。我们可以通过对象引用的方式,可以通过接口回调,构造函数等方式。这个地方就说一下构造函数传递的一个小的问题。一般来说我们传递传参数通过构造函数都是直接传递过去而没有任何问题。但是如果你在activity和fragment之间这样做的话会导致空指针异常。当我们进行横竖屏切换的时候。通过构造函数传递参数就会报空指针异常。 原因:在横竖屏切换的时候会重新的加载activity。而依附于activity的fragment就会按照系统的创建方式重写的创建然后系统的创建方式是通过反射的形式进行创建,那么这个时候我们通过构造函数进行的数据传递就会变成null. 解决问题:为了解决这个问题。官方的解决是通过setArgments进行数据的传递。通过getArgments的方法获取到传递的数据。这样不会导致数据为null。 那为啥会出现这样的为题的我们接下来观察源码流程: 首先我们从我们的子fragment的oncreate方法走起

@CallSuper
public void onCreate(@Nullable Bundle savedInstanceState) {
    mCalled = true;
    restoreChildFragmentState(savedInstanceState);
    if (mChildFragmentManager != null
            && !mChildFragmentManager.isStateAtLeast(Fragment.CREATED)) {
        mChildFragmentManager.dispatchCreate();
    }
}

这个地方我们发现restoreChildFragmentState(savedInstanceState);这个方法的意思不就是对子孩子的数据处理吗,进入该方法。

if (mChildFragmentManager == null) {
    instantiateChildFragmentManager();
}
这个地方主要的就是instantiateChildFragmentManager();这个方法。这个地方是对子fragment的创建和管理操作,点击进入该方法

@Override
public Fragment instantiate(Context context, String className, Bundle arguments) {
    return mHost.instantiate(context, className, arguments);
}

进入方法后我们会发现里面有instantiate(Context context, String className, Bundle arguments) 这个方法。这个方法就是触发父fragment进行系统创建的关键点 mHost.instantiate(context, className, arguments);通过触发instantiate(context, className, arguments);这个方法进行fragment的系统创建。下面我们就来观察系统是如何创建的,

/**
 * Creates an instance of the specified fragment, can be overridden to construct fragments
 * with dependencies, or change the fragment being constructed. By default just calls
 * {@link Fragment#instantiate(Context, String, Bundle)}.
 */
public Fragment instantiate(Context context, String className, Bundle arguments) {
    return Fragment.instantiate(context, className, arguments);
}

接着调用FragmentContainer的instantialte方法触发Fragment。instantite方法。我们发现在数据传递的过程中一直携带者Bundle这个参数。而这个bundle的参数是从oncreate里面的bundle一直传递过来的。下面就是就是见证奇迹的时刻。

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.setArguments(args);
        }
        return f;
    } 

这个地方我没有拷贝完整。想看的可以去看。我靠啥情况和我之前说的一模一样真的是通过发射生成的fragment的啊系统,其实我之前就是由于构造函数传递参数出现问题。造成了恨不必要的麻烦。 f.setArguments(args);这个方法也就是将bundle存储起来所调用的方法。系统的数据调用过程依次就是这样。这时候不免有疑问系统将bundle放到哪里了呢? 接下来接着查找源码

public void setArguments(Bundle args) {
    if (mIndex >= 0 && isStateSaved()) {
        throw new IllegalStateException("Fragment already active and state has been saved");
    }
    mArguments = args;
}

在setArguments中将bundle传递给了一个fragment的全局变量mArguments

// Construction arguments;
Bundle mArguments;

这时候明白了吧,当前的数据会一直存储在fragment中。你需要的时候直接取出就可以了。我能力毕竟有限如果那个地方分析有误。请各位大神指出。避免误人子弟。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值