From 893ee42c721a948dd7d45e88f4c1e85815173205 Mon Sep 17 00:00:00 2001
From: Ricardo Cervera
Allow your activity to restart when a configuration changes, but carry a stateful -{@link java.lang.Object} to the new instance of your activity.
+object to the new instance of your activity.When the Android system shuts down your activity due to a configuration change, the fragments +of your activity that you have marked to retain are not destroyed. You can add such fragments to +your activity to preserve stateful objects.
+ +To retain stateful objects in a fragment during a runtime configuration change:
-To retain an object during a runtime configuration change:
When the Android system shuts down your activity due to a configuration change, it calls {@link -android.app.Activity#onRetainNonConfigurationInstance()} between the {@link -android.app.Activity#onStop()} and {@link android.app.Activity#onDestroy()} callbacks. In your -implementation of {@link android.app.Activity#onRetainNonConfigurationInstance()}, you can return -any {@link java.lang.Object} that you need in order to efficiently restore your state after the -configuration change.
- -A scenario in which this can be valuable is if your application loads a lot of data from the -web. If the user changes the orientation of the device and the activity restarts, your application -must re-fetch the data, which could be slow. What you can do instead is implement -{@link android.app.Activity#onRetainNonConfigurationInstance()} to return an object carrying your -data and then retrieve the data when your activity starts again with {@link -android.app.Activity#getLastNonConfigurationInstance()}. For example:
+For example, define your fragment as follows:
-@Override
-public Object onRetainNonConfigurationInstance() {
- final MyDataObject data = collectMyLoadedData();
- return data;
+public class RetainedFragment extends Fragment {
+
+ // data object we want to retain
+ private MyDataObject data;
+
+ // this method is only called once for this fragment
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ // retain this fragment
+ setRetainInstance(true);
+ }
+
+ public void setData(MyDataObject data) {
+ this.data = data;
+ }
+
+ public MyDataObject getData() {
+ return data;
+ }
}
-Caution: While you can return any object, you +
Caution: While you can store any object, you should never pass an object that is tied to the {@link android.app.Activity}, such as a {@link android.graphics.drawable.Drawable}, an {@link android.widget.Adapter}, a {@link android.view.View} or any other object that's associated with a {@link android.content.Context}. If you do, it will @@ -114,26 +127,51 @@ leak all the views and resources of the original activity instance. (Leaking res means that your application maintains a hold on them and they cannot be garbage-collected, so lots of memory can be lost.)
-Then retrieve the data when your activity starts again:
+Then use {@link android.app.FragmentManager} to add the fragment to the activity. +You can obtain the data object from the fragment when the activity starts again during runtime +configuration changes. For example, define your activity as follows:
-@Override
-public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
+public class MyActivity extends Activity {
- final MyDataObject data = (MyDataObject) getLastNonConfigurationInstance();
- if (data == null) {
- data = loadMyData();
+ private RetainedFragment dataFragment;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.main);
+
+ // find the retained fragment on activity restarts
+ FragmentManager fm = getFragmentManager();
+ dataFragment = (DataFragment) fm.findFragmentByTag(“data”);
+
+ // create the fragment and data the first time
+ if (dataFragment == null) {
+ // add the fragment
+ dataFragment = new DataFragment();
+ fm.beginTransaction().add(dataFragment, “data”).commit();
+ // load the data from the web
+ dataFragment.setData(loadMyData());
+ }
+
+ // the data is available in dataFragment.getData()
+ ...
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ // store the data in the fragment
+ dataFragment.setData(collectMyLoadedData());
}
- ...
}
-In this case, {@link android.app.Activity#getLastNonConfigurationInstance()} returns the data -saved by {@link android.app.Activity#onRetainNonConfigurationInstance()}. If {@code data} is null -(which happens when the activity starts due to any reason other than a configuration change) then -this code loads the data object from the original source.
+In this example, {@link android.app.Activity#onCreate(Bundle) onCreate()} adds a fragment +or restores a reference to it. {@link android.app.Activity#onCreate(Bundle) onCreate()} also +stores the stateful object inside the fragment instance. +{@link android.app.Activity#onDestroy() onDestroy()} updates the stateful object inside the +retained fragment instance.