am b46ed763: Add new Fragment API for explicitly saving/restoring state.
* commit 'b46ed7636be9341b6ce0b158b3d86f34a437e6da':
Add new Fragment API for explicitly saving/restoring state.
diff --git a/api/current.xml b/api/current.xml
index 117ecf9..acea195 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -30627,6 +30627,19 @@
<parameter name="hasMenu" type="boolean">
</parameter>
</method>
+<method name="setInitialSavedState"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="state" type="android.app.Fragment.SavedState">
+</parameter>
+</method>
<method name="setRetainInstance"
return="void"
abstract="false"
@@ -30718,6 +30731,53 @@
</parameter>
</constructor>
</class>
+<class name="Fragment.SavedState"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dest" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<field name="CREATOR"
+ type="android.os.Parcelable.ClassLoaderCreator"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
<class name="FragmentBreadCrumbs"
extends="android.view.ViewGroup"
abstract="false"
@@ -31151,6 +31211,19 @@
<parameter name="listener" type="android.app.FragmentManager.OnBackStackChangedListener">
</parameter>
</method>
+<method name="saveFragmentInstanceState"
+ return="android.app.Fragment.SavedState"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="f" type="android.app.Fragment">
+</parameter>
+</method>
<field name="POP_BACK_STACK_INCLUSIVE"
type="int"
transient="false"
@@ -150858,6 +150931,31 @@
>
</field>
</interface>
+<interface name="Parcelable.ClassLoaderCreator"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable.Creator">
+</implements>
+<method name="createFromParcel"
+ return="T"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="source" type="android.os.Parcel">
+</parameter>
+<parameter name="loader" type="java.lang.ClassLoader">
+</parameter>
+</method>
+</interface>
<interface name="Parcelable.Creator"
abstract="true"
static="true"
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 69cb27e..a61147a 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1875,7 +1875,7 @@
}
deliverNewIntents(r, intents);
if (resumed) {
- mInstrumentation.callActivityOnResume(r.activity);
+ r.activity.performResume();
r.activity.mTemporaryPause = false;
}
}
@@ -2831,7 +2831,7 @@
}
deliverResults(r, res.results);
if (resumed) {
- mInstrumentation.callActivityOnResume(r.activity);
+ r.activity.performResume();
r.activity.mTemporaryPause = false;
}
}
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 6f0bbd7..14ffd3b 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -450,6 +450,51 @@
boolean mCheckedForLoaderManager;
/**
+ * State information that has been retrieved from a fragment instance
+ * through {@link FragmentManager#saveFragmentInstanceState(Fragment)
+ * FragmentManager.saveFragmentInstanceState}.
+ */
+ public static class SavedState implements Parcelable {
+ final Bundle mState;
+
+ SavedState(Bundle state) {
+ mState = state;
+ }
+
+ SavedState(Parcel in, ClassLoader loader) {
+ mState = in.readBundle();
+ if (loader != null && mState != null) {
+ mState.setClassLoader(loader);
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeBundle(mState);
+ }
+
+ public static final Parcelable.ClassLoaderCreator<SavedState> CREATOR
+ = new Parcelable.ClassLoaderCreator<SavedState>() {
+ public SavedState createFromParcel(Parcel in) {
+ return new SavedState(in, null);
+ }
+
+ public SavedState createFromParcel(Parcel in, ClassLoader loader) {
+ return new SavedState(in, loader);
+ }
+
+ public SavedState[] newArray(int size) {
+ return new SavedState[size];
+ }
+ };
+ }
+
+ /**
* Thrown by {@link Fragment#instantiate(Context, String, Bundle)} when
* there is an instantiation failure.
*/
@@ -624,6 +669,22 @@
}
/**
+ * Set the initial saved state that this Fragment should restore itself
+ * from when first being constructed, as returned by
+ * {@link FragmentManager#saveFragmentInstanceState(Fragment)
+ * FragmentManager.saveFragmentInstanceState}.
+ *
+ * @param state The state the fragment should be restored from.
+ */
+ public void setInitialSavedState(SavedState state) {
+ if (mIndex >= 0) {
+ throw new IllegalStateException("Fragment already active");
+ }
+ mSavedFragmentState = state != null && state.mState != null
+ ? state.mState : null;
+ }
+
+ /**
* Optional target for this fragment. This may be used, for example,
* if this fragment is being started by another, and when done wants to
* give a result back to the first. The target set here is retained
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 0da656f..2164ada 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -274,6 +274,30 @@
public abstract Fragment getFragment(Bundle bundle, String key);
/**
+ * Save the current instance state of the given Fragment. This can be
+ * used later when creating a new instance of the Fragment and adding
+ * it to the fragment manager, to have it create itself to match the
+ * current state returned here. Note that there are limits on how
+ * this can be used:
+ *
+ * <ul>
+ * <li>The Fragment must currently be attached to the FragmentManager.
+ * <li>A new Fragment created using this saved state must be the same class
+ * type as the Fragment it was created from.
+ * <li>The saved state can not contain dependencies on other fragments --
+ * that is it can't use {@link #putFragment(Bundle, String, Fragment)} to
+ * store a fragment reference because that reference may not be valid when
+ * this saved state is later used. Likewise the Fragment's target and
+ * result code are not included in this state.
+ * </ul>
+ *
+ * @param f The Fragment whose state is to be saved.
+ * @return The generated state. This will be null if there was no
+ * interesting state created by the fragment.
+ */
+ public abstract Fragment.SavedState saveFragmentInstanceState(Fragment f);
+
+ /**
* Print the FragmentManager's state into the given stream.
*
* @param prefix Text to print at the front of each line.
@@ -492,6 +516,19 @@
}
@Override
+ public Fragment.SavedState saveFragmentInstanceState(Fragment fragment) {
+ if (fragment.mIndex < 0) {
+ throw new IllegalStateException("Fragment " + fragment
+ + " is not currently in the FragmentManager");
+ }
+ if (fragment.mState > Fragment.INITIALIZING) {
+ Bundle result = saveFragmentBasicState(fragment);
+ return result != null ? new Fragment.SavedState(result) : null;
+ }
+ return null;
+ }
+
+ @Override
public String toString() {
StringBuilder sb = new StringBuilder(128);
sb.append("FragmentManager{");
@@ -715,7 +752,6 @@
if (f.mView != null) {
f.mView.setSaveFromParentEnabled(false);
if (f.mHidden) f.mView.setVisibility(View.GONE);
- f.restoreViewState();
f.onViewCreated(f.mView, f.mSavedFragmentState);
}
}
@@ -747,7 +783,6 @@
container.addView(f.mView);
}
if (f.mHidden) f.mView.setVisibility(View.GONE);
- f.restoreViewState();
f.onViewCreated(f.mView, f.mSavedFragmentState);
}
}
@@ -759,6 +794,7 @@
+ " did not call through to super.onActivityCreated()");
}
if (f.mView != null) {
+ f.restoreViewState();
}
f.mSavedFragmentState = null;
}
@@ -1375,6 +1411,8 @@
}
if (mStateArray == null) {
mStateArray = new SparseArray<Parcelable>();
+ } else {
+ mStateArray.clear();
}
f.mView.saveHierarchyState(mStateArray);
if (mStateArray.size() > 0) {
@@ -1383,6 +1421,32 @@
}
}
+ Bundle saveFragmentBasicState(Fragment f) {
+ Bundle result = null;
+
+ if (mStateBundle == null) {
+ mStateBundle = new Bundle();
+ }
+ f.onSaveInstanceState(mStateBundle);
+ if (!mStateBundle.isEmpty()) {
+ result = mStateBundle;
+ mStateBundle = null;
+ }
+
+ if (f.mView != null) {
+ saveFragmentViewState(f);
+ if (f.mSavedViewState != null) {
+ if (result == null) {
+ result = new Bundle();
+ }
+ result.putSparseParcelableArray(
+ FragmentManagerImpl.VIEW_STATE_TAG, f.mSavedViewState);
+ }
+ }
+
+ return result;
+ }
+
Parcelable saveAllState() {
// Make sure all pending operations have now been executed to get
// our state update-to-date.
@@ -1407,25 +1471,7 @@
active[i] = fs;
if (f.mState > Fragment.INITIALIZING && fs.mSavedFragmentState == null) {
- if (mStateBundle == null) {
- mStateBundle = new Bundle();
- }
- f.onSaveInstanceState(mStateBundle);
- if (!mStateBundle.isEmpty()) {
- fs.mSavedFragmentState = mStateBundle;
- mStateBundle = null;
- }
-
- if (f.mView != null) {
- saveFragmentViewState(f);
- if (f.mSavedViewState != null) {
- if (fs.mSavedFragmentState == null) {
- fs.mSavedFragmentState = new Bundle();
- }
- fs.mSavedFragmentState.putSparseParcelableArray(
- FragmentManagerImpl.VIEW_STATE_TAG, f.mSavedViewState);
- }
- }
+ fs.mSavedFragmentState = saveFragmentBasicState(f);
if (f.mTarget != null) {
if (f.mTarget.mIndex < 0) {
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 6b35215..e9ed676 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -1980,6 +1980,9 @@
}
}
+ if (creator instanceof Parcelable.ClassLoaderCreator<?>) {
+ return ((Parcelable.ClassLoaderCreator<T>)creator).createFromParcel(this, loader);
+ }
return creator.createFromParcel(this);
}
diff --git a/core/java/android/os/Parcelable.java b/core/java/android/os/Parcelable.java
index 0a4b60f..594fbb2 100644
--- a/core/java/android/os/Parcelable.java
+++ b/core/java/android/os/Parcelable.java
@@ -113,4 +113,22 @@
*/
public T[] newArray(int size);
}
+
+ /**
+ * Specialization of {@link Creator} that allows you to receive the
+ * ClassLoader the object is being created in.
+ */
+ public interface ClassLoaderCreator<T> extends Creator<T> {
+ /**
+ * Create a new instance of the Parcelable class, instantiating it
+ * from the given Parcel whose data had previously been written by
+ * {@link Parcelable#writeToParcel Parcelable.writeToParcel()} and
+ * using the given ClassLoader.
+ *
+ * @param source The Parcel to read the object's data from.
+ * @param loader The ClassLoader that this object is being created in.
+ * @return Returns a new instance of the Parcelable class.
+ */
+ public T createFromParcel(Parcel source, ClassLoader loader);
+ }
}