含参Fragment的官方构建方法

含参Fragment的官方构建方法

​ 在Android Studio 按照如下方式新建一个Fragment
这里写图片描述
2

这里写图片描述

​ 在选项中勾选默认的三个选项,这样就可以见到Android Studio自动帮你生成好的Fragment模板,在模板代码中可以看到如下段落
这里写图片描述

​ 贴一下源码

  /**
     * Use this factory method to create a new instance of
     * this fragment using the provided parameters.
     *
     * @param param1 Parameter 1.
     * @param param2 Parameter 2.
     * @return A new instance of fragment BlankFragment.
     */
    // TODO: Rename and change types and number of parameters
    public static BlankFragment newInstance(String param1, String param2) {
        BlankFragment fragment = new BlankFragment();
        Bundle args = new Bundle();
        args.putString(ARG_PARAM1, param1);
        args.putString(ARG_PARAM2, param2);
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            mParam1 = getArguments().getString(ARG_PARAM1);
            mParam2 = getArguments().getString(ARG_PARAM2);
        }
    }

​ 注释中写到

使用这个工厂方法来创造这个碎片(Fragment)使用参数的实例。

参数1 Parameter1

参数2 Parameter2

得到一个新的碎片实例(BlankFragment)

要做的事情:改变参数的名称,类型和数量

​ 可以看到,紧接着在注释下面的方法newInstance传入两个参数String param1, String param2。然后返回一个BlankFragment实例,那么这个就是注释中所说的工厂方法了。

​ 再看方法体内,先新建了一个无参的BlankFragment实例,然后紧接着建立了一个Bundle对象,这个类我们在Activity中也见过,应该熟悉了,当我们需要保存Activity中的数据的时候会用到它,这样重建Activity的时候就可以载入这些数据

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

这样,我们可以预想到,在解决Fragment的参数的问题是也是用到了差不多的方式,,果不其然,紧接着在newInstance方法之后就重写了onCreate方法,OK,这样心里就有底了,我们先接着看newInstance方法。

在新建了Bundle对象后,用 args.putString(ARG_PARAM1, param1); args.putString(ARG_PARAM1, param1); 的方式在Bundle对象中保存了我们传入的两个参数,然后调用了BlankFragment的父类也就是Fragment的方法 setArguments(args) 将Bundle设置给我们新建的fragment,也就是说,这个方法所有的Fragment都有,那么,这个 setArguments(args) 是什么呢?我们看一下它的代码。

/**
     * Supply the construction arguments for this fragment.
     * The arguments supplied here will be retained across fragment destroy and
     * creation.
     * <p>This method cannot be called if the fragment is added to a FragmentManager and
     * if {@link #isStateSaved()} would return true.</p>
     */
    public void setArguments(Bundle args) {
        if (mIndex >= 0 && isStateSaved()) {
            throw new IllegalStateException("Fragment already active and state has been saved");
        }
        mArguments = args;
    }

翻译一下它的注释

给这个碎片(Fragment)提供构造参数,在这里提供的参数将在这个碎片从创造(create)到销毁(distory)的过程中保持存在,如果这个碎片被添加到了一个碎片管理器(FragmentManager)则这个方法不能被调用if {@link #isStateSaved()} 会返回true

哈,难怪它长的这么像Setter呢,原来就是一个再正宗不过的Setter罢了,为Fragment的内部成员变量赋值,mArguments想来应该就是就是Fragment保存的Bundle了,果不其然,我们在上面找到了

// Construction arguments;
    Bundle mArguments;

方法体内还有一个简单的判断语句判断该fragment是否被添加到了FragmentManager,如果是的话将抛出异常,不能为该fragment设置成员变量Bundle。

OK,一个blankfragment被完成创建并返回,就这样你得到了一个新鲜出炉的Fragment对象了。

既然有Setter,那么我么紧接着在下面就找到了Getter,等会我们再OnCreate中会用到

  /**
     * Return the arguments supplied when the fragment was instantiated,
     * if any.
     */
    final public Bundle getArguments() {
        return mArguments;
    }

非常简单,我们在这里就不再做翻译和解释了。

抓紧时间看剩下的onCreate方法,我们注意到,在onCreate方法中它传入了一个叫做savedInstanceState的Bundle,然而这个Bundle与我们构造器的传参没有关系,而是和Activity的onCreate一样是用来载入之前被销毁时保存的数据的,真正的传参内容是在下方的if语句中,判断 getArguments()返回值是否为空,若不为空则对两个成员变量进行赋值mParam1 = getArguments().getString(ARG_PARAM1); 到这里,构建一个含参Fragment的任务就完成了。

到这里,可能还会有同学有疑问,为什么构造含参的Fragment构造器需要这么麻烦的方法呢,我们在Google关于Fragment的官方文档里可以找到这样一段说明

Default constructor. Every fragment must have an empty constructor, so it can be instantiated when restoring its activity’s state. It is strongly recommended that subclasses do not have other constructors with parameters, since these constructors will not be called when the fragment is re-instantiated; instead, arguments can be supplied by the caller with setArguments(Bundle) and later retrieved by the Fragment with getArguments().

Applications should generally not implement a constructor. Prefer onAttach(Context) instead. It is the first place application code can run where the fragment is ready to be used - the point where the fragment is actually associated with its context. Some applications may also want to implement onInflate(Activity, AttributeSet, Bundle) to retrieve attributes from a layout resource, although note this happens when the fragment is attached.

默认的构造器,每一个碎片一定更要有一个空的构造器,这样它才能在它的活动重启时被实例化。这里强烈推荐它的子类不要含有其他含参的构造器,因为这些构造器在这个碎片被重新实例化的时候不会被调用,取而代之的是,参数可以在setArguments(Bundle)的调用中被应用并且随后通过碎片的getArguments()被检索得到。

应用并不会实现一个构造器方法,相反的使用 onAttach(Context) 。这是当碎片准备被使用时第一个能执行应用代码的地方——也是碎片实际和它的context相关联的地方,一些应用可能也会调用onInflate(Activity, AttributeSet, Bundle) 从布局文件中来检索属性,要注意当碎片被关联式会发生这种情况。

这段说明对为什么不能使用含参数的Fragment构造器已经说明得很清楚了,在接下来的 instantiate(Context context, String fname, Bundle args)方法(当活动重启时会调用的得到fragment实例的方法)中我们也可以找到下面这段代码


        Fragment f = (Fragment)e.newInstance();
        if(args != null) {
            args.setClassLoader(f.getClass().getClassLoader());
            f.mArguments = args;
        }

和我们之前的代码简直契合完美。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值