Android – 保存/恢复片段状态
我有一个活动,我经历了几个片段。 在每个片段中,我有几个视图( EditText, ListView, Map
等)。
我怎样才能保存在那个时候显示的片段的实例? 当activity是onPause() --> onResume()
时,我需要它工作。 另外我需要它的工作,当我从另一个片段(从后台popup)返回。
从主要Activity
我叫第一个片段,然后从我打电话给下一个片段。
代码为我的活动:
public class Activity_Main extends FragmentActivity{ public static Fragment_1 fragment_1; public static Fragment_2 fragment_2; public static Fragment_3 fragment_3; public static FragmentManager fragmentManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); fragment_1 = new Fragment_1(); fragment_2 = new Fragment_2(); fragment_3 = new Fragment_3(); fragmentManager = getSupportFragmentManager(); FragmentTransaction transaction_1 = fragmentManager.beginTransaction(); transaction_1.replace(R.id.content_frame, fragment_1); transaction_1.commit(); }}
那么这里是我的一个片段的代码:
public class Fragment_1 extends Fragment { private EditText title; private Button go_next; @Override public View onCreateView(final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_1, container, false); title = (EditText) rootView.findViewById(R.id.title); go_next = (Button) rootView.findViewById(R.id.go_next); image.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { FragmentTransaction transaction_2 = Activity_Main.fragmentManager .beginTransaction(); transaction_2.replace(R.id.content_frame, Activity_Main.fragment_2); transaction_2.addToBackStack(null); transaction_2.commit(); }); }}
我搜查了很多信息,但没有清楚。 有人可以给一个清楚的解决scheme和一个例子吗?
当一个片段移动到后台时,它不会被破坏。 所有的实例variables都保留在那里。 所以这是保存你的数据的地方。 在onActivityCreated
检查以下条件:
- 捆绑!= null? 如果是的话,这就是数据保存的地方(可能是方向改变)。
- 数据是否保存在实例variables中? 如果是的话,从他们身上恢复你的状态(或者什么都不做,因为一切都是应该的)。
- 否则你的片段是第一次显示,重新创build一切。
编辑:这是一个例子
public class ExampleFragment extends Fragment { private List<String> myData; @Override public void onSaveInstanceState(final Bundle outState) { super.onSaveInstanceState(outState); outState.putSerializable("list", (Serializable) myData); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); if (savedInstanceState != null) { //probably orientation change myData = (List<String>) savedInstanceState.getSerializable("list"); } else { if (myData != null) { //returning from backstack, data is fine, do nothing } else { //newly created, compute data myData = computeData(); } } } }
尝试这个 :
@Override protected void onPause() { super.onPause(); if (getSupportFragmentManager().findFragmentByTag("MyFragment") != null) getSupportFragmentManager().findFragmentByTag("MyFragment").setRetainInstance(true); } @Override protected void onResume() { super.onResume(); if (getSupportFragmentManager().findFragmentByTag("MyFragment") != null) getSupportFragmentManager().findFragmentByTag("MyFragment").getRetainInstance(); }
希望这会有所帮助。
你也可以写在清单文件中的活动标签:
android:configChanges="orientation|screenSize"
祝你好运 !!!
Android片段有一些优点和一些缺点。 这个片段的最大缺点是,当你想使用一个片段时,你可以创build它。 当你使用它时, oncreateview
调用片段的oncreateview
。 如果要保留片段中组件的状态,则必须保存片段状态,并且必须在下一个显示中加载其状态。 这使得片段视图有点慢和怪异。
我find了一个解决scheme,我使用了这个解决scheme:“一切都很好,每个人都可以尝试”。
当第一次运行oncreateview
,将视图创build为全局variables。 当你第二次调用这个片段oncreateview
被再次调用时,你可以返回这个全局视图。 片段组件状态将被保留。
View view; @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { setActionBar(null); if(view!=null){ if((ViewGroup)view.getParent()!=null) ((ViewGroup)view.getParent()).removeView(view); return view; } view = inflater.inflate(R.layout.mylayout, container, false);
如上所述: 为什么使用Fragment#setRetainInstance(boolean)?
你也可以像这样使用片段方法setRetainInstance(true)
:
public class MyFragment extends Fragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // keep the fragment and all its data across screen rotation setRetainInstance(true); } }
为了保存Fragment状态,你需要实现onSaveInstanceState()
:“同样也是一个活动,你可以使用一个Bundle保留一个片段的状态,以防活动的进程被终止,并且你需要恢复片段状态活动被重新创build,您可以在onSaveInstanceState()
callback中保存状态,并在onCreate()
, onCreateView()
或onActivityCreated()
过程中恢复。有关保存状态的更多信息,请参阅活动文档。
http://developer.android.com/guide/components/fragments.html#Lifecycle
我不太确定这个问题是否还困扰着你,因为已经有好几个月了。 但我想分享我如何处理这个问题。 这里是源代码:
int FLAG = 0; private View rootView; private LinearLayout parentView; /** * The fragment argument representing the section number for this fragment. */ private static final String ARG_SECTION_NUMBER = "section_number"; /** * Returns a new instance of this fragment for the given section number. */ public static Fragment2 newInstance(Bundle bundle) { Fragment2 fragment = new Fragment2(); Bundle args = bundle; fragment.setArguments(args); return fragment; } public Fragment2() { } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { super.onCreateView(inflater, container, savedInstanceState); Log.e("onCreateView","onCreateView"); if(FLAG!=12321){ rootView = inflater.inflate(R.layout.fragment_create_new_album, container, false); changeFLAG(12321); } parentView=new LinearLayout(getActivity()); parentView.addView(rootView); return parentView; } /* (non-Javadoc) * @see android.support.v4.app.Fragment#onDestroy() */ @Override public void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); Log.e("onDestroy","onDestroy"); } /* (non-Javadoc) * @see android.support.v4.app.Fragment#onStart() */ @Override public void onStart() { // TODO Auto-generated method stub super.onStart(); Log.e("onstart","onstart"); } /* (non-Javadoc) * @see android.support.v4.app.Fragment#onStop() */ @Override public void onStop() { // TODO Auto-generated method stub super.onStop(); if(false){ Bundle savedInstance=getArguments(); LinearLayout viewParent; viewParent= (LinearLayout) rootView.getParent(); viewParent.removeView(rootView); } parentView.removeView(rootView); Log.e("onStop","onstop"); } @Override public void onPause() { super.onPause(); Log.e("onpause","onpause"); } @Override public void onResume() { super.onResume(); Log.e("onResume","onResume"); }
这是MainActivity:
/** * Fragment managing the behaviors, interactions and presentation of the * navigation drawer. */ private NavigationDrawerFragment mNavigationDrawerFragment; /** * Used to store the last screen title. For use in * {@link #restoreActionBar()}. */ public static boolean fragment2InstanceExists=false; public static Fragment2 fragment2=null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); setContentView(R.layout.activity_main); mNavigationDrawerFragment = (NavigationDrawerFragment) getSupportFragmentManager() .findFragmentById(R.id.navigation_drawer); mTitle = getTitle(); // Set up the drawer. mNavigationDrawerFragment.setUp(R.id.navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout)); } @Override public void onNavigationDrawerItemSelected(int position) { // update the main content by replacing fragments FragmentManager fragmentManager = getSupportFragmentManager(); FragmentTransaction fragmentTransaction=fragmentManager.beginTransaction(); switch(position){ case 0: fragmentTransaction.addToBackStack(null); fragmentTransaction.replace(R.id.container, Fragment1.newInstance(position+1)).commit(); break; case 1: Bundle bundle=new Bundle(); bundle.putInt("source_of_create",CommonMethods.CREATE_FROM_ACTIVITY); if(!fragment2InstanceExists){ fragment2=Fragment2.newInstance(bundle); fragment2InstanceExists=true; } fragmentTransaction.addToBackStack(null); fragmentTransaction.replace(R.id.container, fragment2).commit(); break; case 2: fragmentTransaction.addToBackStack(null); fragmentTransaction.replace(R.id.container, FolderExplorerFragment.newInstance(position+1)).commit(); break; default: break; } }
parentView
是关键点。 通常,当onCreateView
,我们只使用return rootView
。 但是现在,我将rootView添加到parentView
,然后返回parentView
。 为了防止“指定的孩子已经有一个父母,你必须调用removeView()
…”错误,我们需要调用parentView.removeView(rootView)
,或者我提供的方法是无用的。 我也想分享我是如何find它的。 首先,我设置了一个布尔值来指示实例是否存在。 当实例存在时, rootView
将不会被再次膨胀。 但是,logcat给了孩子已经有一个父母的事情,所以我决定使用另一个父母作为中间父视图。 这是如何工作的。
希望对你有帮助。
您可以从fragmentManager中获取当前的片段。 如果片段pipe理器中没有它们,您可以创buildFragment_1
public class MainActivity extends FragmentActivity { public static Fragment_1 fragment_1; public static Fragment_2 fragment_2; public static Fragment_3 fragment_3; public static FragmentManager fragmentManager; @Override protected void onCreate(Bundle arg0) { super.onCreate(arg0); setContentView(R.layout.main); fragment_1 = (Fragment_1) fragmentManager.findFragmentByTag("fragment1"); fragment_2 =(Fragment_2) fragmentManager.findFragmentByTag("fragment2"); fragment_3 = (Fragment_3) fragmentManager.findFragmentByTag("fragment3"); if(fragment_1==null && fragment_2==null && fragment_3==null){ fragment_1 = new Fragment_1(); fragmentManager.beginTransaction().replace(R.id.content_frame, fragment_1, "fragment1").commit(); } } }
也可以使用setRetainInstance
为true它会做什么它忽略onDestroy()
方法在片段和您的应用程序将回到地面和操作系统杀死您的应用程序分配更多的内存,您将需要保存所需的所有数据在onSaveInstanceState
包
public class Fragment_1 extends Fragment { private EditText title; private Button go_next; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setRetainInstance(true); //Will ignore onDestroy Method (Nested Fragments no need this if parent have it) } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { onRestoreInstanceStae(savedInstanceState); return super.onCreateView(inflater, container, savedInstanceState); } //Here you can restore saved data in onSaveInstanceState Bundle private void onRestoreInstanceState(Bundle savedInstanceState){ if(savedInstanceState!=null){ String SomeText = savedInstanceState.getString("title"); } } //Here you Save your data @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putString("title", "Some Text"); } }