summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.xml41
-rw-r--r--core/java/android/app/BackStackRecord.java48
-rw-r--r--core/java/android/app/Fragment.java37
-rw-r--r--core/java/android/app/FragmentManager.java97
-rw-r--r--core/java/android/app/FragmentTransaction.java25
-rw-r--r--core/java/android/app/ListFragment.java6
6 files changed, 219 insertions, 35 deletions
diff --git a/api/current.xml b/api/current.xml
index b2330be..3843f67 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -30529,6 +30529,21 @@
visibility="public"
>
</method>
+<method name="onViewCreated"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="view" type="android.view.View">
+</parameter>
+<parameter name="savedInstanceState" type="android.os.Bundle">
+</parameter>
+</method>
<method name="registerForContextMenu"
return="void"
abstract="false"
@@ -31262,6 +31277,19 @@
<parameter name="name" type="java.lang.String">
</parameter>
</method>
+<method name="attach"
+ return="android.app.FragmentTransaction"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fragment" type="android.app.Fragment">
+</parameter>
+</method>
<method name="commit"
return="int"
abstract="true"
@@ -31284,6 +31312,19 @@
visibility="public"
>
</method>
+<method name="detach"
+ return="android.app.FragmentTransaction"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fragment" type="android.app.Fragment">
+</parameter>
+</method>
<method name="disallowAddToBackStack"
return="android.app.FragmentTransaction"
abstract="true"
diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java
index 1d217f0..09e3d76 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -169,6 +169,8 @@ final class BackStackRecord extends FragmentTransaction implements
static final int OP_REMOVE = 3;
static final int OP_HIDE = 4;
static final int OP_SHOW = 5;
+ static final int OP_DETACH = 6;
+ static final int OP_ATTACH = 7;
static final class Op {
Op next;
@@ -401,6 +403,32 @@ final class BackStackRecord extends FragmentTransaction implements
return this;
}
+ public FragmentTransaction detach(Fragment fragment) {
+ //if (fragment.mImmediateActivity == null) {
+ // throw new IllegalStateException("Fragment not added: " + fragment);
+ //}
+
+ Op op = new Op();
+ op.cmd = OP_DETACH;
+ op.fragment = fragment;
+ addOp(op);
+
+ return this;
+ }
+
+ public FragmentTransaction attach(Fragment fragment) {
+ //if (fragment.mImmediateActivity == null) {
+ // throw new IllegalStateException("Fragment not added: " + fragment);
+ //}
+
+ Op op = new Op();
+ op.cmd = OP_ATTACH;
+ op.fragment = fragment;
+ addOp(op);
+
+ return this;
+ }
+
public FragmentTransaction setCustomAnimations(int enter, int exit) {
mEnterAnim = enter;
mExitAnim = exit;
@@ -567,6 +595,16 @@ final class BackStackRecord extends FragmentTransaction implements
f.mNextAnim = op.enterAnim;
mManager.showFragment(f, mTransition, mTransitionStyle);
} break;
+ case OP_DETACH: {
+ Fragment f = op.fragment;
+ f.mNextAnim = op.exitAnim;
+ mManager.detachFragment(f, mTransition, mTransitionStyle);
+ } break;
+ case OP_ATTACH: {
+ Fragment f = op.fragment;
+ f.mNextAnim = op.enterAnim;
+ mManager.attachFragment(f, mTransition, mTransitionStyle);
+ } break;
default: {
throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
}
@@ -627,6 +665,16 @@ final class BackStackRecord extends FragmentTransaction implements
mManager.hideFragment(f,
FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
} break;
+ case OP_DETACH: {
+ Fragment f = op.fragment;
+ mManager.attachFragment(f,
+ FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
+ } break;
+ case OP_ATTACH: {
+ Fragment f = op.fragment;
+ mManager.detachFragment(f,
+ FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
+ } break;
default: {
throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
}
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 53dc7c8..dd158f9 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -52,6 +52,7 @@ final class FragmentState implements Parcelable {
final int mContainerId;
final String mTag;
final boolean mRetainInstance;
+ final boolean mDetached;
final Bundle mArguments;
Bundle mSavedFragmentState;
@@ -66,6 +67,7 @@ final class FragmentState implements Parcelable {
mContainerId = frag.mContainerId;
mTag = frag.mTag;
mRetainInstance = frag.mRetainInstance;
+ mDetached = frag.mDetached;
mArguments = frag.mArguments;
}
@@ -77,6 +79,7 @@ final class FragmentState implements Parcelable {
mContainerId = in.readInt();
mTag = in.readString();
mRetainInstance = in.readInt() != 0;
+ mDetached = in.readInt() != 0;
mArguments = in.readBundle();
mSavedFragmentState = in.readBundle();
}
@@ -103,6 +106,7 @@ final class FragmentState implements Parcelable {
mInstance.mContainerId = mContainerId;
mInstance.mTag = mTag;
mInstance.mRetainInstance = mRetainInstance;
+ mInstance.mDetached = mDetached;
mInstance.mFragmentManager = activity.mFragments;
return mInstance;
@@ -120,6 +124,7 @@ final class FragmentState implements Parcelable {
dest.writeInt(mContainerId);
dest.writeString(mTag);
dest.writeInt(mRetainInstance ? 1 : 0);
+ dest.writeInt(mDetached ? 1 : 0);
dest.writeBundle(mArguments);
dest.writeBundle(mSavedFragmentState);
}
@@ -321,8 +326,9 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener
static final int INITIALIZING = 0; // Not yet created.
static final int CREATED = 1; // Created.
static final int ACTIVITY_CREATED = 2; // The activity has finished its creation.
- static final int STARTED = 3; // Created and started, not resumed.
- static final int RESUMED = 4; // Created started and resumed.
+ static final int STOPPED = 3; // Fully created, not started.
+ static final int STARTED = 4; // Created and started, not resumed.
+ static final int RESUMED = 5; // Created started and resumed.
int mState = INITIALIZING;
@@ -404,6 +410,9 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener
// from the user.
boolean mHidden;
+ // Set to true when the app has requested that this fragment be detached.
+ boolean mDetached;
+
// If set this fragment would like its instance retained across
// configuration changes.
boolean mRetainInstance;
@@ -511,23 +520,27 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener
}
}
- void restoreViewState() {
+ final void restoreViewState() {
if (mSavedViewState != null) {
mView.restoreHierarchyState(mSavedViewState);
mSavedViewState = null;
}
}
- void setIndex(int index) {
+ final void setIndex(int index) {
mIndex = index;
mWho = "android:fragment:" + mIndex;
}
- void clearIndex() {
+ final void clearIndex() {
mIndex = -1;
mWho = null;
}
+ final boolean isInBackStack() {
+ return mBackStackNesting > 0;
+ }
+
/**
* Subclasses can not override equals().
*/
@@ -947,6 +960,19 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener
}
/**
+ * Called immediately after {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)}
+ * has returned, but before any saved state has been restored in to the view.
+ * This gives subclasses a chance to initialize themselves once
+ * they know their view hierarchy has been completely created. The fragment's
+ * view hierarchy is not however attached to its parent at this point.
+ * @param view The View returned by {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)}.
+ * @param savedInstanceState If non-null, this fragment is being re-constructed
+ * from a previous saved state as given here.
+ */
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ }
+
+ /**
* Called to have the fragment instantiate its user interface view.
* This is optional, and non-graphical fragments can return null (which
* is the default implementation). This will be called between
@@ -1280,6 +1306,7 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener
writer.print(" mFromLayout="); writer.print(mFromLayout);
writer.print(" mInLayout="); writer.println(mInLayout);
writer.print(prefix); writer.print("mHidden="); writer.print(mHidden);
+ writer.print(" mDetached="); writer.print(mDetached);
writer.print(" mRetainInstance="); writer.print(mRetainInstance);
writer.print(" mRetaining="); writer.print(mRetaining);
writer.print(" mHasMenu="); writer.println(mHasMenu);
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index ab60cf0..0da656f 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -714,13 +714,14 @@ final class FragmentManagerImpl extends FragmentManager {
null, f.mSavedFragmentState);
if (f.mView != null) {
f.mView.setSaveFromParentEnabled(false);
+ if (f.mHidden) f.mView.setVisibility(View.GONE);
f.restoreViewState();
- if (f.mHidden) f.mView.setVisibility(View.GONE);
+ f.onViewCreated(f.mView, f.mSavedFragmentState);
}
}
case Fragment.CREATED:
if (newState > Fragment.CREATED) {
- if (DEBUG) Log.v(TAG, "moveto CONTENT: " + f);
+ if (DEBUG) Log.v(TAG, "moveto ACTIVITY_CREATED: " + f);
if (!f.mFromLayout) {
ViewGroup container = null;
if (f.mContainerId != 0) {
@@ -744,9 +745,10 @@ final class FragmentManagerImpl extends FragmentManager {
anim.start();
}
container.addView(f.mView);
- f.restoreViewState();
}
- if (f.mHidden) f.mView.setVisibility(View.GONE);
+ if (f.mHidden) f.mView.setVisibility(View.GONE);
+ f.restoreViewState();
+ f.onViewCreated(f.mView, f.mSavedFragmentState);
}
}
@@ -756,10 +758,13 @@ final class FragmentManagerImpl extends FragmentManager {
throw new SuperNotCalledException("Fragment " + f
+ " did not call through to super.onActivityCreated()");
}
+ if (f.mView != null) {
+ }
f.mSavedFragmentState = null;
}
case Fragment.ACTIVITY_CREATED:
- if (newState > Fragment.ACTIVITY_CREATED) {
+ case Fragment.STOPPED:
+ if (newState > Fragment.STOPPED) {
if (DEBUG) Log.v(TAG, "moveto STARTED: " + f);
f.mCalled = false;
f.onStart();
@@ -803,9 +808,10 @@ final class FragmentManagerImpl extends FragmentManager {
+ " did not call through to super.onStop()");
}
}
+ case Fragment.STOPPED:
case Fragment.ACTIVITY_CREATED:
if (newState < Fragment.ACTIVITY_CREATED) {
- if (DEBUG) Log.v(TAG, "movefrom CONTENT: " + f);
+ if (DEBUG) Log.v(TAG, "movefrom ACTIVITY_CREATED: " + f);
if (f.mView != null) {
// Need to save the current view state if not
// done already.
@@ -971,32 +977,36 @@ final class FragmentManagerImpl extends FragmentManager {
if (mAdded == null) {
mAdded = new ArrayList<Fragment>();
}
- mAdded.add(fragment);
- makeActive(fragment);
if (DEBUG) Log.v(TAG, "add: " + fragment);
- fragment.mAdded = true;
- fragment.mRemoving = false;
- if (fragment.mHasMenu) {
- mNeedMenuInvalidate = true;
- }
- if (moveToStateNow) {
- moveToState(fragment);
+ makeActive(fragment);
+ if (!fragment.mDetached) {
+ mAdded.add(fragment);
+ fragment.mAdded = true;
+ fragment.mRemoving = false;
+ if (fragment.mHasMenu) {
+ mNeedMenuInvalidate = true;
+ }
+ if (moveToStateNow) {
+ moveToState(fragment);
+ }
}
}
public void removeFragment(Fragment fragment, int transition, int transitionStyle) {
if (DEBUG) Log.v(TAG, "remove: " + fragment + " nesting=" + fragment.mBackStackNesting);
- mAdded.remove(fragment);
- final boolean inactive = fragment.mBackStackNesting <= 0;
- if (fragment.mHasMenu) {
- mNeedMenuInvalidate = true;
- }
- fragment.mAdded = false;
- fragment.mRemoving = true;
- moveToState(fragment, inactive ? Fragment.INITIALIZING : Fragment.CREATED,
- transition, transitionStyle);
- if (inactive) {
- makeInactive(fragment);
+ final boolean inactive = !fragment.isInBackStack();
+ if (!fragment.mDetached || inactive) {
+ mAdded.remove(fragment);
+ if (fragment.mHasMenu) {
+ mNeedMenuInvalidate = true;
+ }
+ fragment.mAdded = false;
+ fragment.mRemoving = true;
+ moveToState(fragment, inactive ? Fragment.INITIALIZING : Fragment.CREATED,
+ transition, transitionStyle);
+ if (inactive) {
+ makeInactive(fragment);
+ }
}
}
@@ -1052,6 +1062,39 @@ final class FragmentManagerImpl extends FragmentManager {
}
}
+ public void detachFragment(Fragment fragment, int transition, int transitionStyle) {
+ if (DEBUG) Log.v(TAG, "detach: " + fragment);
+ if (!fragment.mDetached) {
+ fragment.mDetached = true;
+ if (fragment.mAdded) {
+ // We are not already in back stack, so need to remove the fragment.
+ mAdded.remove(fragment);
+ if (fragment.mHasMenu) {
+ mNeedMenuInvalidate = true;
+ }
+ fragment.mAdded = false;
+ fragment.mRemoving = true;
+ moveToState(fragment, Fragment.CREATED, transition, transitionStyle);
+ }
+ }
+ }
+
+ public void attachFragment(Fragment fragment, int transition, int transitionStyle) {
+ if (DEBUG) Log.v(TAG, "attach: " + fragment);
+ if (fragment.mDetached) {
+ fragment.mDetached = false;
+ if (!fragment.mAdded) {
+ mAdded.add(fragment);
+ fragment.mAdded = true;
+ fragment.mRemoving = false;
+ if (fragment.mHasMenu) {
+ mNeedMenuInvalidate = true;
+ }
+ moveToState(fragment, mCurState, transition, transitionStyle);
+ }
+ }
+ }
+
public Fragment findFragmentById(int id) {
if (mActive != null) {
// First look through added fragments.
@@ -1594,7 +1637,7 @@ final class FragmentManagerImpl extends FragmentManager {
}
public void dispatchStop() {
- moveToState(Fragment.ACTIVITY_CREATED, false);
+ moveToState(Fragment.STOPPED, false);
}
public void dispatchDestroy() {
diff --git a/core/java/android/app/FragmentTransaction.java b/core/java/android/app/FragmentTransaction.java
index 0cc774d..15b873b 100644
--- a/core/java/android/app/FragmentTransaction.java
+++ b/core/java/android/app/FragmentTransaction.java
@@ -87,6 +87,31 @@ public abstract class FragmentTransaction {
public abstract FragmentTransaction show(Fragment fragment);
/**
+ * Detach the given fragment from the UI. This is the same state as
+ * when it is put on the back stack: the fragment is removed from
+ * the UI, however its state is still being actively managed by the
+ * fragment manager. When going into this state its view hierarchy
+ * is destroyed.
+ *
+ * @param fragment The fragment to be detached.
+ *
+ * @return Returns the same FragmentTransaction instance.
+ */
+ public abstract FragmentTransaction detach(Fragment fragment);
+
+ /**
+ * Re-attach a fragment after it had previously been deatched from
+ * the UI with {@link #detach(Fragment)}. This
+ * causes its view hierarchy to be re-created, attached to the UI,
+ * and displayed.
+ *
+ * @param fragment The fragment to be attached.
+ *
+ * @return Returns the same FragmentTransaction instance.
+ */
+ public abstract FragmentTransaction attach(Fragment fragment);
+
+ /**
* @return <code>true</code> if this transaction contains no operations,
* <code>false</code> otherwise.
*/
diff --git a/core/java/android/app/ListFragment.java b/core/java/android/app/ListFragment.java
index 6e2f4b6..a5ee26c 100644
--- a/core/java/android/app/ListFragment.java
+++ b/core/java/android/app/ListFragment.java
@@ -195,11 +195,11 @@ public class ListFragment extends Fragment {
}
/**
- * Attach to list view once Fragment is ready to run.
+ * Attach to list view once the view hierarchy has been created.
*/
@Override
- public void onActivityCreated(Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
ensureList();
}