为什么要在Fragment中使用setArgument?
我们知道,当app的屏幕进行旋转或者其他的配置变化的时候,Fragment会执行它的周期变化,重新创建Fragment并加载(除非设置了setRetainInstance(true)),那么在重建的时候Fragment中的变量就会被重新初始化,运行中的状态将无法保留。
setArgument中的Bundle可以用来存放各种需要保持的数据,即使Fragment由于配置改变而重建,这些保存的数据也不会被清除。
下面我们将通过一个实例来测试一下,在实例的Fragment中共有3个TextView和一个Button,为了使测试的内容更清晰,下面把三个TextView对应的字符串列表如下:
textview1->banana, textview2->apple, textview3->pear
对应的三个字符串:
- mParam1: 在Fragment.newInstance中传入,并保存在setArgument中,但是在点击按钮时未更新到Argument中
- mParam2: Fragment中的私有变量,和Argument无任何交互
- mParam3: 在Fragment.newInstance中传入,并保存在setArgument中,并且在点击按钮时更新到了Argument中
测试程序的布局代码和java代码如下:
Fragment部局文件的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.bcoder.myapplication.TestFragment" android:orientation="vertical"> <!-- TODO: Update blank fragment layout --> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="textview1" android:id="@+id/textview1"/> <TextView android:text="TextView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/textview2"/> <TextView android:text="TextView" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/textview3"/> <Button android:text="Button" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/button1"/> </LinearLayout> |
Fragment的Java代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
package com.bcoder.myapplication; import android.content.Context; import android.net.Uri; import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.TextView; public class TestFragment extends Fragment { private static final String ARG_PARAM1 = "param1"; private static final String ARG_PARAM3 = "param3"; private String mParam1; private String mParam2; private String mParam3; TextView mTextView1; TextView mTextView2; TextView mTextView3; Button button1; View fragmentView; public TestFragment() { // Required empty public constructor } public static TestFragment newInstance(String param1, String param3) { TestFragment fragment = new TestFragment(); Bundle args = new Bundle(); args.putString(ARG_PARAM1, param1); args.putString(ARG_PARAM3, param3); fragment.setArguments(args); return fragment; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (getArguments() != null) { mParam1 = getArguments().getString(ARG_PARAM1); mParam3 = getArguments().getString(ARG_PARAM3); } } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { fragmentView = inflater.inflate(R.layout.fragment_test, container, false); initViews(); mTextView1.setText(mParam1); mTextView2.setText(mParam2); mTextView3.setText(mParam3); return fragmentView; } private void initViews() { mTextView1 = (TextView) fragmentView.findViewById(R.id.textview1); mTextView2 = (TextView) fragmentView.findViewById(R.id.textview2); mTextView3 = (TextView) fragmentView.findViewById(R.id.textview3); button1 = (Button) fragmentView.findViewById(R.id.button1); button1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { mParam1 = "banana2"; mTextView1.setText(mParam1); mParam2 = "apple"; mTextView2.setText(mParam2); mParam3 = "pear click"; getArguments().putString(ARG_PARAM3, mParam3); mTextView3.setText(mParam3); } }); } @Override public void onAttach(Context context) { super.onAttach(context); } @Override public void onDetach() { super.onDetach(); } } |
主Activity的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
package com.bcoder.myapplication; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.widget.LinearLayout; public class MainActivity extends AppCompatActivity { LinearLayout layoutContainer; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initViews(); TestFragment fragment = TestFragment.newInstance("banana", "pear"); FragmentManager manager = getSupportFragmentManager(); FragmentTransaction transaction = manager.beginTransaction(); transaction.add(R.id.layoutFragmentContainer, fragment); transaction.commit(); } private void initViews() { layoutContainer = (LinearLayout) findViewById(R.id.layoutFragmentContainer); } } |
主Activity的布局文件代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.bcoder.myapplication.MainActivity" android:orientation="vertical"> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/layoutFragmentContainer"> </LinearLayout> </LinearLayout> |
程序启动时显示默认如下内容:
textview1和textview3的值取自getArgument并显示在了屏幕上,当点击按钮时会重新给三个String变量赋值,并显示到textview中,如下图:
这时三个字符串变量都有了新的值,那么当我们把屏幕进行一下旋转操作后,看结果如何呢?
由图可知,字符串1回到了最初的状态(创建Fragment时传入的值),而字符串2被清除了。
字符串3因为在点击按钮的时候重新被保存在getArgument中,而没有任何的变化的被保留下来了。
因此大家在给Fragment传入参数的时候最好通过setArgument进行保存,而不是简单的通过一个变量进行保存。
注意:
- setArgument只能在Fragment中创建后(MyFragment fragment = new MyFragment())立即调用,如果在Fragment被附加到Activity中后再调用就会报错,可以在按钮的点击事件中添加一下setArgument的调用进行一下试验,应用将被异常终止。