Android Fragment实例化:newInstance()

时间:2017-08-23 12:29:57

标签: java android android-fragments

我阅读了许多文章和StackOverflow答案,但仍然无法理解为什么我们需要工厂方法来创建片段的实例。

以下Fragment类都可以正常工作。

具有两个构造函数的片段:

public class CtorFragment extends Fragment {
    private static final String KEY = "the_key";

    public CtorFragment() {
        // Android calls the default constructor so default constructor must be explicitly defined.
        // As we have another constructor, Android won't create a default constructor for us.
    }

    public CtorFragment(String s) {
        // Set the arguments.
        Bundle bundle = new Bundle();
        bundle.putString(KEY, s);

        setArguments(bundle);
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
        View fragment = inflater.inflate(R.layout.fragment_my, container, false);
        TextView textView = (TextView) fragment.findViewById(R.id.textView);

        // Use getArguments() to get the String argument set by the constructor with parameter.
        textView.setText(getArguments().getString(KEY));
        return fragment;
    }
}

使用静态工厂方法的片段:

public class StaticFragment extends Fragment {
    private static final String KEY = "the_key";

    public static StaticFragment newInstance(String s) {
        StaticFragment fragment = new StaticFragment();
        // Set the arguments.
        Bundle bundle = new Bundle();
        bundle.putString(KEY, s);

        fragment.setArguments(bundle);
        return fragment;
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
        View fragment = inflater.inflate(R.layout.fragment_my, container, false);
        TextView textView = (TextView) fragment.findViewById(R.id.textView);

        // Use getArguments() to get the String argument set by the constructor with parameter.
        textView.setText(getArguments().getString(KEY));
        return fragment;
    }
}

您能解释一下为什么每个人(包括谷歌)"强烈推荐"那个用静态工厂方法?是否有一些关键的东西让我和其他来自非Android背景的人失踪了?

是否我们必须定义两个方法(构造函数)而不是一个(静态工厂方法),这会导致所有的麻烦?

2 个答案:

答案 0 :(得分:2)

  

仍然无法理解为什么我们需要工厂方法来创建Fragment的实例

"需要"是一个强有力的词。你不需要"需要"工厂方法。你需要:

  • 公共零参数构造函数,理想情况下为空;以及

  • 一种有组织的方法,可以在配置发生变化的情况下设置片段

  

您能解释一下为什么每个人(包括谷歌)"强烈推荐"有静态工厂方法的那个?

如果Java类上没有显式构造函数,则会自动获得一个空的公共零参数构造函数,这是框架创建片段所需的构造函数。

如果您创建一个带参数的构造函数(例如CtorFragment(String s)),那么您还必须记住创建公共零参数构造函数(CtorFragment())。你可能还记得这样做。许多缺乏经验的程序员不会。

编写工厂方法实现与非零参数构造函数相同的目标,而不会破坏自动创建的零参数构造函数。

如果您是一位经验丰富的Java程序员,并且您不喜欢工厂方法,并且您可以读取堆栈跟踪,并且记得添加公共零参数构造函数,那么欢迎您创建其他构造函数并使用它们。

答案 1 :(得分:1)

newInstance的目的主要是为Fragment设置初始值。如果我们使用片段的默认构造函数,我们就不能将参数设置为发送初始值的方法。

以下是https://stackoverflow.com/a/9245510/4758255引用的更多细节说明:

如果Android决定稍后重新创建Fragment,它将调用片段的无参数构造函数。所以重载构造函数不是解决方案。

话虽如此,将内容传递给Fragment以便在Android重新创建片段后可用的方法是将包传递给setArguments方法。

因此,例如,如果我们想将一个整数传递给片段,我们会使用类似的东西:

public static MyFragment newInstance(int someInt) {
    MyFragment myFragment = new MyFragment();

    Bundle args = new Bundle();
    args.putInt("someInt", someInt);
    myFragment.setArguments(args);

    return myFragment;
}

稍后在片段onCreate()中,您可以使用以下方法访问该整数:

getArguments().getInt("someInt", 0);

即使片段以某种方式由Android重新创建,也可以使用此Bundle。

另请注意:setArguments只能在片段附加到活动之前调用。

这种方法也记录在android开发人员参考:https://developer.android.com/reference/android/app/Fragment.html