今天要解决的问题是Fragment状态持久化,所谓Fragment状态持久化就是当窗口发生配置变化时涉及到的状态保存的问题,今天的例子就是解决窗口横竖屏切换问题。窗口在横竖屏切换的过程中是先销毁后重建的。这里的状态就是Fragment类中的成员变量的值了。
我当时就纳闷了,既然销毁了,那怎么保存状态呢?后来我看了很多例子查阅很多资料得到了一些信息。一种就是Fragment的状态变量保存在Fragment.onSaveInstanceState方法中,同样的道理,Activity的状态变量保存在Activity.onSaveInstanceState中。另外一种就是用Fragment.setArgument方法来设置保存状态变量的Bundle对象。
Bundle bundle = new Bundle();
bundle.putString =("name", "ddfdd");
setArgument(bundle);
通过Fragment.getArgument()方法获取状态变量值。
这时候有碰到问题了,就算这些值被保存下来了,但是切换横竖屏时,窗口配置变了,原来的Fragment就会被销毁,之前所做的努力不是都白费了吗?当然问题来了,当然得解决问题了,这时候需要在Activity.onSaveInstanceState方法把这个Fragment保存下来,这时候Fragment的状态变量也随之保存下来了。怎么来保存和获取呢?则是通过FragmentManager.putFragment 和FragmentManager.getFragment 分别来获取这些变量。然后就可以操作了。需要注意的在Fragment声明的成员变量需要在Framgnet.onActivityCreate方法中恢复这些状态变量。
package com.example.fragment_persistence; import android.annotation.SuppressLint; import android.app.Activity; import android.app.FragmentManager; import android.os.Bundle; import android.view.Menu; import android.view.View; import android.widget.Toast; @SuppressLint({ "NewApi", "ShowToast" }) public class FragmentPersistenceActivity extends Activity { private MyFragment fragment; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_fragment_persistence); FragmentManager fragmentManager = getFragmentManager(); if(fragment != null){ fragment = (MyFragment) fragmentManager.getFragment(savedInstanceState, "fragment"); } if(fragment ==null){ fragment =(MyFragment) fragmentManager.findFragmentById(R.id.myFragment); } } public void onClick_SetFramentField(View view){ if(fragment != null){ fragment.name="name:新的字段值"; fragment.getArguments().putString("name", "arg:新设置的值"); Toast.makeText(this, "成功为name赋值", Toast.LENGTH_LONG).show(); } } public void onClick_getfragmentFieldValue(View view){ Toast.makeText(this, fragment.name, Toast.LENGTH_LONG).show(); Toast.makeText(this,fragment.getArguments().getString("name"), Toast.LENGTH_LONG).show(); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.fragment_persistence, menu); return true; } @Override protected void onSaveInstanceState(Bundle outState) { // TODO Auto-generated method stub if(fragment != null){ getFragmentManager().putFragment(outState, "fragment",fragment); } super.onSaveInstanceState(outState); } }
package com.example.fragment_persistence; import android.annotation.SuppressLint; import android.app.Activity; import android.app.Fragment; import android.os.Bundle; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @SuppressLint("NewApi") public class MyFragment extends Fragment{ public String name = "name:default"; @Override public void onSaveInstanceState(Bundle outState) { // TODO Auto-generated method stub outState.putString("name", name); super.onSaveInstanceState(outState); } @Override public void onActivityCreated(Bundle savedInstanceState) { // TODO Auto-generated method stub if(savedInstanceState != null){ String s = savedInstanceState.getString("name"); if(s != null){ name = s; } } super.onActivityCreated(savedInstanceState); } @Override public void onInflate(Activity activity, AttributeSet attrs, Bundle savedInstanceState) { // TODO Auto-generated method stub if(getArguments() == null){ Bundle bundle = new Bundle(); bundle.putString("name", "arg:default"); setArguments(bundle); } super.onInflate(activity, attrs, savedInstanceState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // TODO Auto-generated method stub View view = inflater.inflate(R.layout.myfragment, container, false); return view; } }
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <EditText android:id="@+id/editText" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </LinearLayout>
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <Button android:id="@+id/button_01" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="设置Fragment中的字段" android:onClick="onClick_SetFramentField" /> <Button android:id="@+id/button_02" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="获取Fragment中的字段" android:onClick="onClick_getfragmentFieldValue" /> <fragment android:id="@+id/myFragment" class="com.example.fragment_persistence.MyFragment" android:layout_width="fill_parent" android:layout_height="fill_parent" /> </LinearLayout>
这里涉及到了三个状态,两个同为名name的字段和参数,另一个是EditText 这个控件的ID被当做键进行保存的。
这个问题也是我测试本例出现的问题,在网上查了一下原因是出现了空指针异常。