Merge "Nested fragments." into jb-mr1-dev

This commit is contained in:
Dianne Hackborn
2012-09-06 11:41:47 -07:00
committed by Android (Google) Code Review
5 changed files with 425 additions and 118 deletions

View File

@@ -3348,6 +3348,7 @@ package android.app {
method public final boolean equals(java.lang.Object); method public final boolean equals(java.lang.Object);
method public final android.app.Activity getActivity(); method public final android.app.Activity getActivity();
method public final android.os.Bundle getArguments(); method public final android.os.Bundle getArguments();
method public final android.app.FragmentManager getChildFragmentManager();
method public final android.app.FragmentManager getFragmentManager(); method public final android.app.FragmentManager getFragmentManager();
method public final int getId(); method public final int getId();
method public android.app.LoaderManager getLoaderManager(); method public android.app.LoaderManager getLoaderManager();
@@ -3399,6 +3400,7 @@ package android.app {
method public void onStop(); method public void onStop();
method public void onTrimMemory(int); method public void onTrimMemory(int);
method public void onViewCreated(android.view.View, android.os.Bundle); method public void onViewCreated(android.view.View, android.os.Bundle);
method public void onViewStateRestored(android.os.Bundle);
method public void registerForContextMenu(android.view.View); method public void registerForContextMenu(android.view.View);
method public void setArguments(android.os.Bundle); method public void setArguments(android.os.Bundle);
method public void setHasOptionsMenu(boolean); method public void setHasOptionsMenu(boolean);

View File

@@ -653,8 +653,9 @@ public class Activity extends ContextThemeWrapper
/** Start of user-defined activity results. */ /** Start of user-defined activity results. */
public static final int RESULT_FIRST_USER = 1; public static final int RESULT_FIRST_USER = 1;
static final String FRAGMENTS_TAG = "android:fragments";
private static final String WINDOW_HIERARCHY_TAG = "android:viewHierarchyState"; private static final String WINDOW_HIERARCHY_TAG = "android:viewHierarchyState";
private static final String FRAGMENTS_TAG = "android:fragments";
private static final String SAVED_DIALOG_IDS_KEY = "android:savedDialogIds"; private static final String SAVED_DIALOG_IDS_KEY = "android:savedDialogIds";
private static final String SAVED_DIALOGS_TAG = "android:savedDialogs"; private static final String SAVED_DIALOGS_TAG = "android:savedDialogs";
private static final String SAVED_DIALOG_KEY_PREFIX = "android:dialog_"; private static final String SAVED_DIALOG_KEY_PREFIX = "android:dialog_";
@@ -697,7 +698,7 @@ public class Activity extends ContextThemeWrapper
Object activity; Object activity;
HashMap<String, Object> children; HashMap<String, Object> children;
ArrayList<Fragment> fragments; ArrayList<Fragment> fragments;
SparseArray<LoaderManagerImpl> loaders; HashMap<String, LoaderManagerImpl> loaders;
} }
/* package */ NonConfigurationInstances mLastNonConfigurationInstances; /* package */ NonConfigurationInstances mLastNonConfigurationInstances;
@@ -715,8 +716,14 @@ public class Activity extends ContextThemeWrapper
private int mTitleColor = 0; private int mTitleColor = 0;
final FragmentManagerImpl mFragments = new FragmentManagerImpl(); final FragmentManagerImpl mFragments = new FragmentManagerImpl();
final FragmentContainer mContainer = new FragmentContainer() {
@Override
public View findViewById(int id) {
return Activity.this.findViewById(id);
}
};
SparseArray<LoaderManagerImpl> mAllLoaderManagers; HashMap<String, LoaderManagerImpl> mAllLoaderManagers;
LoaderManagerImpl mLoaderManager; LoaderManagerImpl mLoaderManager;
private static final class ManagedCursor { private static final class ManagedCursor {
@@ -744,6 +751,7 @@ public class Activity extends ContextThemeWrapper
protected static final int[] FOCUSED_STATE_SET = {com.android.internal.R.attr.state_focused}; protected static final int[] FOCUSED_STATE_SET = {com.android.internal.R.attr.state_focused};
@SuppressWarnings("unused")
private final Object mInstanceTracker = StrictMode.trackActivity(this); private final Object mInstanceTracker = StrictMode.trackActivity(this);
private Thread mUiThread; private Thread mUiThread;
@@ -808,19 +816,19 @@ public class Activity extends ContextThemeWrapper
return mLoaderManager; return mLoaderManager;
} }
mCheckedForLoaderManager = true; mCheckedForLoaderManager = true;
mLoaderManager = getLoaderManager(-1, mLoadersStarted, true); mLoaderManager = getLoaderManager(null, mLoadersStarted, true);
return mLoaderManager; return mLoaderManager;
} }
LoaderManagerImpl getLoaderManager(int index, boolean started, boolean create) { LoaderManagerImpl getLoaderManager(String who, boolean started, boolean create) {
if (mAllLoaderManagers == null) { if (mAllLoaderManagers == null) {
mAllLoaderManagers = new SparseArray<LoaderManagerImpl>(); mAllLoaderManagers = new HashMap<String, LoaderManagerImpl>();
} }
LoaderManagerImpl lm = mAllLoaderManagers.get(index); LoaderManagerImpl lm = mAllLoaderManagers.get(who);
if (lm == null) { if (lm == null) {
if (create) { if (create) {
lm = new LoaderManagerImpl(this, started); lm = new LoaderManagerImpl(who, this, started);
mAllLoaderManagers.put(index, lm); mAllLoaderManagers.put(who, lm);
} }
} else { } else {
lm.updateActivity(this); lm.updateActivity(this);
@@ -1025,7 +1033,7 @@ public class Activity extends ContextThemeWrapper
if (mLoaderManager != null) { if (mLoaderManager != null) {
mLoaderManager.doStart(); mLoaderManager.doStart();
} else if (!mCheckedForLoaderManager) { } else if (!mCheckedForLoaderManager) {
mLoaderManager = getLoaderManager(-1, mLoadersStarted, false); mLoaderManager = getLoaderManager(null, mLoadersStarted, false);
} }
mCheckedForLoaderManager = true; mCheckedForLoaderManager = true;
} }
@@ -1601,13 +1609,17 @@ public class Activity extends ContextThemeWrapper
if (mAllLoaderManagers != null) { if (mAllLoaderManagers != null) {
// prune out any loader managers that were already stopped and so // prune out any loader managers that were already stopped and so
// have nothing useful to retain. // have nothing useful to retain.
for (int i=mAllLoaderManagers.size()-1; i>=0; i--) { LoaderManagerImpl loaders[] = new LoaderManagerImpl[mAllLoaderManagers.size()];
LoaderManagerImpl lm = mAllLoaderManagers.valueAt(i); mAllLoaderManagers.values().toArray(loaders);
if (lm.mRetaining) { if (loaders != null) {
retainLoaders = true; for (int i=0; i<loaders.length; i++) {
} else { LoaderManagerImpl lm = loaders[i];
lm.doDestroy(); if (lm.mRetaining) {
mAllLoaderManagers.removeAt(i); retainLoaders = true;
} else {
lm.doDestroy();
mAllLoaderManagers.remove(lm.mWho);
}
} }
} }
} }
@@ -1643,13 +1655,13 @@ public class Activity extends ContextThemeWrapper
return mFragments; return mFragments;
} }
void invalidateFragmentIndex(int index) { void invalidateFragment(String who) {
//Log.v(TAG, "invalidateFragmentIndex: index=" + index); //Log.v(TAG, "invalidateFragmentIndex: index=" + index);
if (mAllLoaderManagers != null) { if (mAllLoaderManagers != null) {
LoaderManagerImpl lm = mAllLoaderManagers.get(index); LoaderManagerImpl lm = mAllLoaderManagers.get(who);
if (lm != null && !lm.mRetaining) { if (lm != null && !lm.mRetaining) {
lm.doDestroy(); lm.doDestroy();
mAllLoaderManagers.remove(index); mAllLoaderManagers.remove(who);
} }
} }
} }
@@ -4739,6 +4751,10 @@ public class Activity extends ContextThemeWrapper
* @param args additional arguments to the dump request. * @param args additional arguments to the dump request.
*/ */
public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
dumpInner(prefix, fd, writer, args);
}
void dumpInner(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
writer.print(prefix); writer.print("Local Activity "); writer.print(prefix); writer.print("Local Activity ");
writer.print(Integer.toHexString(System.identityHashCode(this))); writer.print(Integer.toHexString(System.identityHashCode(this)));
writer.println(" State:"); writer.println(" State:");
@@ -5019,7 +5035,7 @@ public class Activity extends ContextThemeWrapper
Configuration config) { Configuration config) {
attachBaseContext(context); attachBaseContext(context);
mFragments.attachActivity(this); mFragments.attachActivity(this, mContainer, null);
mWindow = PolicyManager.makeNewWindow(this); mWindow = PolicyManager.makeNewWindow(this);
mWindow.setCallback(this); mWindow.setCallback(this);
@@ -5080,10 +5096,14 @@ public class Activity extends ContextThemeWrapper
} }
mFragments.dispatchStart(); mFragments.dispatchStart();
if (mAllLoaderManagers != null) { if (mAllLoaderManagers != null) {
for (int i=mAllLoaderManagers.size()-1; i>=0; i--) { LoaderManagerImpl loaders[] = new LoaderManagerImpl[mAllLoaderManagers.size()];
LoaderManagerImpl lm = mAllLoaderManagers.valueAt(i); mAllLoaderManagers.values().toArray(loaders);
lm.finishRetain(); if (loaders != null) {
lm.doReportStart(); for (int i=0; i<loaders.length; i++) {
LoaderManagerImpl lm = loaders[i];
lm.finishRetain();
lm.doReportStart();
}
} }
} }
} }

View File

@@ -85,7 +85,7 @@ final class FragmentState implements Parcelable {
mSavedFragmentState = in.readBundle(); mSavedFragmentState = in.readBundle();
} }
public Fragment instantiate(Activity activity) { public Fragment instantiate(Activity activity, Fragment parent) {
if (mInstance != null) { if (mInstance != null) {
return mInstance; return mInstance;
} }
@@ -100,7 +100,7 @@ final class FragmentState implements Parcelable {
mSavedFragmentState.setClassLoader(activity.getClassLoader()); mSavedFragmentState.setClassLoader(activity.getClassLoader());
mInstance.mSavedFragmentState = mSavedFragmentState; mInstance.mSavedFragmentState = mSavedFragmentState;
} }
mInstance.setIndex(mIndex); mInstance.setIndex(mIndex, parent);
mInstance.mFromLayout = mFromLayout; mInstance.mFromLayout = mFromLayout;
mInstance.mRestored = true; mInstance.mRestored = true;
mInstance.mFragmentId = mFragmentId; mInstance.mFragmentId = mFragmentId;
@@ -207,6 +207,8 @@ final class FragmentState implements Parcelable {
* with the fragment. * with the fragment.
* <li> {@link #onActivityCreated} tells the fragment that its activity has * <li> {@link #onActivityCreated} tells the fragment that its activity has
* completed its own {@link Activity#onCreate Activity.onCreate()}. * completed its own {@link Activity#onCreate Activity.onCreate()}.
* <li> {@link #onViewStateRestored} tells the fragment that all of the saved
* state of its view hierarchy has been restored.
* <li> {@link #onStart} makes the fragment visible to the user (based on its * <li> {@link #onStart} makes the fragment visible to the user (based on its
* containing activity being started). * containing activity being started).
* <li> {@link #onResume} makes the fragment interacting with the user (based on its * <li> {@link #onResume} makes the fragment interacting with the user (based on its
@@ -412,7 +414,13 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
// Activity this fragment is attached to. // Activity this fragment is attached to.
Activity mActivity; Activity mActivity;
// Private fragment manager for child fragments inside of this one.
FragmentManagerImpl mChildFragmentManager;
// If this Fragment is contained in another Fragment, this is that container.
Fragment mParentFragment;
// The optional identifier for this fragment -- either the container ID if it // The optional identifier for this fragment -- either the container ID if it
// was dynamically added to the view hierarchy, or the ID supplied in // was dynamically added to the view hierarchy, or the ID supplied in
// layout. // layout.
@@ -595,16 +603,26 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
} }
} }
final void restoreViewState() { final void restoreViewState(Bundle savedInstanceState) {
if (mSavedViewState != null) { if (mSavedViewState != null) {
mView.restoreHierarchyState(mSavedViewState); mView.restoreHierarchyState(mSavedViewState);
mSavedViewState = null; mSavedViewState = null;
} }
mCalled = false;
onViewStateRestored(savedInstanceState);
if (!mCalled) {
throw new SuperNotCalledException("Fragment " + this
+ " did not call through to super.onViewStateRestored()");
}
} }
final void setIndex(int index) { final void setIndex(int index, Fragment parent) {
mIndex = index; mIndex = index;
mWho = "android:fragment:" + mIndex; if (parent != null) {
mWho = parent.mWho + ":" + mIndex;
} else {
mWho = "android:fragment:" + mIndex;
}
} }
final boolean isInBackStack() { final boolean isInBackStack() {
@@ -785,11 +803,34 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
* before {@link #getActivity()}, during the time from when the fragment is * before {@link #getActivity()}, during the time from when the fragment is
* placed in a {@link FragmentTransaction} until it is committed and * placed in a {@link FragmentTransaction} until it is committed and
* attached to its activity. * attached to its activity.
*
* <p>If this Fragment is a child of another Fragment, the FragmentManager
* returned here will be the parent's {@link #getChildFragmentManager()}.
*/ */
final public FragmentManager getFragmentManager() { final public FragmentManager getFragmentManager() {
return mFragmentManager; return mFragmentManager;
} }
/**
* Return a private FragmentManager for placing and managing Fragments
* inside of this Fragment.
*/
final public FragmentManager getChildFragmentManager() {
if (mChildFragmentManager == null) {
instantiateChildFragmentManager();
if (mState >= RESUMED) {
mChildFragmentManager.dispatchResume();
} else if (mState >= STARTED) {
mChildFragmentManager.dispatchStart();
} else if (mState >= ACTIVITY_CREATED) {
mChildFragmentManager.dispatchActivityCreated();
} else if (mState >= CREATED) {
mChildFragmentManager.dispatchCreate();
}
}
return mChildFragmentManager;
}
/** /**
* Return true if the fragment is currently added to its activity. * Return true if the fragment is currently added to its activity.
*/ */
@@ -880,6 +921,10 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
* </ul> * </ul>
*/ */
public void setRetainInstance(boolean retain) { public void setRetainInstance(boolean retain) {
if (retain && mParentFragment != null) {
throw new IllegalStateException(
"Can't retain fragements that are nested in other fragments");
}
mRetainInstance = retain; mRetainInstance = retain;
} }
@@ -961,7 +1006,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
throw new IllegalStateException("Fragment " + this + " not attached to Activity"); throw new IllegalStateException("Fragment " + this + " not attached to Activity");
} }
mCheckedForLoaderManager = true; mCheckedForLoaderManager = true;
mLoaderManager = mActivity.getLoaderManager(mIndex, mLoadersStarted, true); mLoaderManager = mActivity.getLoaderManager(mWho, mLoadersStarted, true);
return mLoaderManager; return mLoaderManager;
} }
@@ -1191,7 +1236,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
* {@link #setRetainInstance(boolean)} to retain their instance, * {@link #setRetainInstance(boolean)} to retain their instance,
* as this callback tells the fragment when it is fully associated with * as this callback tells the fragment when it is fully associated with
* the new activity instance. This is called after {@link #onCreateView} * the new activity instance. This is called after {@link #onCreateView}
* and before {@link #onStart()}. * and before {@link #onViewStateRestored(Bundle)}.
* *
* @param savedInstanceState If the fragment is being re-created from * @param savedInstanceState If the fragment is being re-created from
* a previous saved state, this is the state. * a previous saved state, this is the state.
@@ -1199,7 +1244,22 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
public void onActivityCreated(Bundle savedInstanceState) { public void onActivityCreated(Bundle savedInstanceState) {
mCalled = true; mCalled = true;
} }
/**
* Called when all saved state has been restored into the view hierarchy
* of the fragment. This can be used to do initialization based on saved
* state that you are letting the view hierarchy track itself, such as
* whether check box widgets are currently checked. This is called
* after {@link #onActivityCreated(Bundle)} and before
* {@link #onStart()}.
*
* @param savedInstanceState If the fragment is being re-created from
* a previous saved state, this is the state.
*/
public void onViewStateRestored(Bundle savedInstanceState) {
mCalled = true;
}
/** /**
* Called when the Fragment is visible to the user. This is generally * Called when the Fragment is visible to the user. This is generally
* tied to {@link Activity#onStart() Activity.onStart} of the containing * tied to {@link Activity#onStart() Activity.onStart} of the containing
@@ -1212,7 +1272,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
mLoadersStarted = true; mLoadersStarted = true;
if (!mCheckedForLoaderManager) { if (!mCheckedForLoaderManager) {
mCheckedForLoaderManager = true; mCheckedForLoaderManager = true;
mLoaderManager = mActivity.getLoaderManager(mIndex, mLoadersStarted, false); mLoaderManager = mActivity.getLoaderManager(mWho, mLoadersStarted, false);
} }
if (mLoaderManager != null) { if (mLoaderManager != null) {
mLoaderManager.doStart(); mLoaderManager.doStart();
@@ -1305,7 +1365,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
// + " mLoaderManager=" + mLoaderManager); // + " mLoaderManager=" + mLoaderManager);
if (!mCheckedForLoaderManager) { if (!mCheckedForLoaderManager) {
mCheckedForLoaderManager = true; mCheckedForLoaderManager = true;
mLoaderManager = mActivity.getLoaderManager(mIndex, mLoadersStarted, false); mLoaderManager = mActivity.getLoaderManager(mWho, mLoadersStarted, false);
} }
if (mLoaderManager != null) { if (mLoaderManager != null) {
mLoaderManager.doDestroy(); mLoaderManager.doDestroy();
@@ -1530,6 +1590,14 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
writer.print(prefix); writer.print("mActivity="); writer.print(prefix); writer.print("mActivity=");
writer.println(mActivity); writer.println(mActivity);
} }
if (mChildFragmentManager != null) {
writer.print(prefix); writer.print("mChildFragmentManager=");
writer.println(mChildFragmentManager);
}
if (mParentFragment != null) {
writer.print(prefix); writer.print("mParentFragment=");
writer.println(mParentFragment);
}
if (mArguments != null) { if (mArguments != null) {
writer.print(prefix); writer.print("mArguments="); writer.println(mArguments); writer.print(prefix); writer.print("mArguments="); writer.println(mArguments);
} }
@@ -1564,23 +1632,229 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
writer.print(prefix); writer.println("Loader Manager:"); writer.print(prefix); writer.println("Loader Manager:");
mLoaderManager.dump(prefix + " ", fd, writer, args); mLoaderManager.dump(prefix + " ", fd, writer, args);
} }
if (mChildFragmentManager != null) {
writer.print(prefix); writer.println("Child Fragment Manager:");
mChildFragmentManager.dump(prefix + " ", fd, writer, args);
}
}
Fragment findFragmentByWho(String who) {
if (who.equals(mWho)) {
return this;
}
if (mChildFragmentManager != null) {
return mChildFragmentManager.findFragmentByWho(who);
}
return null;
}
void instantiateChildFragmentManager() {
mChildFragmentManager = new FragmentManagerImpl();
mChildFragmentManager.attachActivity(mActivity, new FragmentContainer() {
@Override
public View findViewById(int id) {
if (mView == null) {
throw new IllegalStateException("Fragment does not have a view");
}
return mView.findViewById(id);
}
}, this);
}
void performCreate(Bundle savedInstanceState) {
mCalled = false;
onCreate(savedInstanceState);
if (!mCalled) {
throw new SuperNotCalledException("Fragment " + this
+ " did not call through to super.onCreate()");
}
if (savedInstanceState != null) {
Parcelable p = savedInstanceState.getParcelable(Activity.FRAGMENTS_TAG);
if (p != null) {
if (mChildFragmentManager == null) {
instantiateChildFragmentManager();
}
mChildFragmentManager.restoreAllState(p, null);
mChildFragmentManager.dispatchCreate();
}
}
}
void performActivityCreated(Bundle savedInstanceState) {
mCalled = false;
onActivityCreated(savedInstanceState);
if (!mCalled) {
throw new SuperNotCalledException("Fragment " + this
+ " did not call through to super.onActivityCreated()");
}
if (mChildFragmentManager != null) {
mChildFragmentManager.dispatchActivityCreated();
}
} }
void performStart() { void performStart() {
if (mChildFragmentManager != null) {
mChildFragmentManager.noteStateNotSaved();
mChildFragmentManager.execPendingActions();
}
mCalled = false;
onStart(); onStart();
if (!mCalled) {
throw new SuperNotCalledException("Fragment " + this
+ " did not call through to super.onStart()");
}
if (mChildFragmentManager != null) {
mChildFragmentManager.dispatchStart();
}
if (mLoaderManager != null) { if (mLoaderManager != null) {
mLoaderManager.doReportStart(); mLoaderManager.doReportStart();
} }
} }
void performResume() {
if (mChildFragmentManager != null) {
mChildFragmentManager.execPendingActions();
}
mCalled = false;
onResume();
if (!mCalled) {
throw new SuperNotCalledException("Fragment " + this
+ " did not call through to super.onResume()");
}
if (mChildFragmentManager != null) {
mChildFragmentManager.dispatchResume();
mChildFragmentManager.execPendingActions();
}
}
void performConfigurationChanged(Configuration newConfig) {
onConfigurationChanged(newConfig);
if (mChildFragmentManager != null) {
mChildFragmentManager.dispatchConfigurationChanged(newConfig);
}
}
void performLowMemory() {
onLowMemory();
if (mChildFragmentManager != null) {
mChildFragmentManager.dispatchLowMemory();
}
}
void performTrimMemory(int level) {
onTrimMemory(level);
if (mChildFragmentManager != null) {
mChildFragmentManager.dispatchTrimMemory(level);
}
}
boolean performCreateOptionsMenu(Menu menu, MenuInflater inflater) {
boolean show = false;
if (!mHidden) {
if (mHasMenu && mMenuVisible) {
show = true;
onCreateOptionsMenu(menu, inflater);
}
if (mChildFragmentManager != null) {
show |= mChildFragmentManager.dispatchCreateOptionsMenu(menu, inflater);
}
}
return show;
}
boolean performPrepareOptionsMenu(Menu menu) {
boolean show = false;
if (!mHidden) {
if (mHasMenu && mMenuVisible) {
show = true;
onPrepareOptionsMenu(menu);
}
if (mChildFragmentManager != null) {
show |= mChildFragmentManager.dispatchPrepareOptionsMenu(menu);
}
}
return show;
}
boolean performOptionsItemSelected(MenuItem item) {
if (!mHidden) {
if (mHasMenu && mMenuVisible) {
if (onOptionsItemSelected(item)) {
return true;
}
}
if (mChildFragmentManager != null) {
if (mChildFragmentManager.dispatchOptionsItemSelected(item)) {
return true;
}
}
}
return false;
}
boolean performContextItemSelected(MenuItem item) {
if (!mHidden) {
if (onContextItemSelected(item)) {
return true;
}
if (mChildFragmentManager != null) {
if (mChildFragmentManager.dispatchContextItemSelected(item)) {
return true;
}
}
}
return false;
}
void performOptionsMenuClosed(Menu menu) {
if (!mHidden) {
if (mHasMenu && mMenuVisible) {
onOptionsMenuClosed(menu);
}
if (mChildFragmentManager != null) {
mChildFragmentManager.dispatchOptionsMenuClosed(menu);
}
}
}
void performSaveInstanceState(Bundle outState) {
onSaveInstanceState(outState);
if (mChildFragmentManager != null) {
Parcelable p = mChildFragmentManager.saveAllState();
if (p != null) {
outState.putParcelable(Activity.FRAGMENTS_TAG, p);
}
}
}
void performPause() {
if (mChildFragmentManager != null) {
mChildFragmentManager.dispatchPause();
}
mCalled = false;
onPause();
if (!mCalled) {
throw new SuperNotCalledException("Fragment " + this
+ " did not call through to super.onPause()");
}
}
void performStop() { void performStop() {
if (mChildFragmentManager != null) {
mChildFragmentManager.dispatchStop();
}
mCalled = false;
onStop(); onStop();
if (!mCalled) {
throw new SuperNotCalledException("Fragment " + this
+ " did not call through to super.onStop()");
}
if (mLoadersStarted) { if (mLoadersStarted) {
mLoadersStarted = false; mLoadersStarted = false;
if (!mCheckedForLoaderManager) { if (!mCheckedForLoaderManager) {
mCheckedForLoaderManager = true; mCheckedForLoaderManager = true;
mLoaderManager = mActivity.getLoaderManager(mIndex, mLoadersStarted, false); mLoaderManager = mActivity.getLoaderManager(mWho, mLoadersStarted, false);
} }
if (mLoaderManager != null) { if (mLoaderManager != null) {
if (mActivity == null || !mActivity.mChangingConfigurations) { if (mActivity == null || !mActivity.mChangingConfigurations) {
@@ -1593,9 +1867,29 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
} }
void performDestroyView() { void performDestroyView() {
if (mChildFragmentManager != null) {
mChildFragmentManager.dispatchDestroyView();
}
mCalled = false;
onDestroyView(); onDestroyView();
if (!mCalled) {
throw new SuperNotCalledException("Fragment " + this
+ " did not call through to super.onDestroyView()");
}
if (mLoaderManager != null) { if (mLoaderManager != null) {
mLoaderManager.doReportNextStart(); mLoaderManager.doReportNextStart();
} }
} }
void performDestroy() {
if (mChildFragmentManager != null) {
mChildFragmentManager.dispatchDestroy();
}
mCalled = false;
onDestroy();
if (!mCalled) {
throw new SuperNotCalledException("Fragment " + this
+ " did not call through to super.onDestroy()");
}
}
} }

View File

@@ -20,7 +20,6 @@ import android.animation.Animator;
import android.animation.AnimatorInflater; import android.animation.AnimatorInflater;
import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorListenerAdapter;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
@@ -30,7 +29,6 @@ import android.os.Parcelable;
import android.util.DebugUtils; import android.util.DebugUtils;
import android.util.Log; import android.util.Log;
import android.util.LogWriter; import android.util.LogWriter;
import android.util.Slog;
import android.util.SparseArray; import android.util.SparseArray;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
@@ -380,6 +378,13 @@ final class FragmentManagerState implements Parcelable {
}; };
} }
/**
* Callbacks from FragmentManagerImpl to its container.
*/
interface FragmentContainer {
public View findViewById(int id);
}
/** /**
* Container for fragments associated with an activity. * Container for fragments associated with an activity.
*/ */
@@ -410,6 +415,8 @@ final class FragmentManagerImpl extends FragmentManager {
int mCurState = Fragment.INITIALIZING; int mCurState = Fragment.INITIALIZING;
Activity mActivity; Activity mActivity;
FragmentContainer mContainer;
Fragment mParent;
boolean mNeedMenuInvalidate; boolean mNeedMenuInvalidate;
boolean mStateSaved; boolean mStateSaved;
@@ -585,7 +592,11 @@ final class FragmentManagerImpl extends FragmentManager {
sb.append("FragmentManager{"); sb.append("FragmentManager{");
sb.append(Integer.toHexString(System.identityHashCode(this))); sb.append(Integer.toHexString(System.identityHashCode(this)));
sb.append(" in "); sb.append(" in ");
DebugUtils.buildShortClassTag(mActivity, sb); if (mParent != null) {
DebugUtils.buildShortClassTag(mParent, sb);
} else {
DebugUtils.buildShortClassTag(mActivity, sb);
}
sb.append("}}"); sb.append("}}");
return sb.toString(); return sb.toString();
} }
@@ -681,6 +692,11 @@ final class FragmentManagerImpl extends FragmentManager {
} }
writer.print(prefix); writer.println("FragmentManager misc state:"); writer.print(prefix); writer.println("FragmentManager misc state:");
writer.print(prefix); writer.print(" mActivity="); writer.println(mActivity);
writer.print(prefix); writer.print(" mContainer="); writer.println(mContainer);
if (mParent != null) {
writer.print(prefix); writer.print(" mParent="); writer.println(mParent);
}
writer.print(prefix); writer.print(" mCurState="); writer.print(mCurState); writer.print(prefix); writer.print(" mCurState="); writer.print(mCurState);
writer.print(" mStateSaved="); writer.print(mStateSaved); writer.print(" mStateSaved="); writer.print(mStateSaved);
writer.print(" mDestroyed="); writer.println(mDestroyed); writer.print(" mDestroyed="); writer.println(mDestroyed);
@@ -809,7 +825,9 @@ final class FragmentManagerImpl extends FragmentManager {
} }
} }
f.mActivity = mActivity; f.mActivity = mActivity;
f.mFragmentManager = mActivity.mFragments; f.mParentFragment = mParent;
f.mFragmentManager = mParent != null
? mParent.mChildFragmentManager : mActivity.mFragments;
f.mCalled = false; f.mCalled = false;
f.onAttach(mActivity); f.onAttach(mActivity);
if (!f.mCalled) { if (!f.mCalled) {
@@ -817,14 +835,9 @@ final class FragmentManagerImpl extends FragmentManager {
+ " did not call through to super.onAttach()"); + " did not call through to super.onAttach()");
} }
mActivity.onAttachFragment(f); mActivity.onAttachFragment(f);
if (!f.mRetaining) { if (!f.mRetaining) {
f.mCalled = false; f.performCreate(f.mSavedFragmentState);
f.onCreate(f.mSavedFragmentState);
if (!f.mCalled) {
throw new SuperNotCalledException("Fragment " + f
+ " did not call through to super.onCreate()");
}
} }
f.mRetaining = false; f.mRetaining = false;
if (f.mFromLayout) { if (f.mFromLayout) {
@@ -845,7 +858,7 @@ final class FragmentManagerImpl extends FragmentManager {
if (!f.mFromLayout) { if (!f.mFromLayout) {
ViewGroup container = null; ViewGroup container = null;
if (f.mContainerId != 0) { if (f.mContainerId != 0) {
container = (ViewGroup)mActivity.findViewById(f.mContainerId); container = (ViewGroup)mContainer.findViewById(f.mContainerId);
if (container == null && !f.mRestored) { if (container == null && !f.mRestored) {
throwException(new IllegalArgumentException( throwException(new IllegalArgumentException(
"No view found for id 0x" "No view found for id 0x"
@@ -873,14 +886,9 @@ final class FragmentManagerImpl extends FragmentManager {
} }
} }
f.mCalled = false; f.performActivityCreated(f.mSavedFragmentState);
f.onActivityCreated(f.mSavedFragmentState);
if (!f.mCalled) {
throw new SuperNotCalledException("Fragment " + f
+ " did not call through to super.onActivityCreated()");
}
if (f.mView != null) { if (f.mView != null) {
f.restoreViewState(); f.restoreViewState(f.mSavedFragmentState);
} }
f.mSavedFragmentState = null; f.mSavedFragmentState = null;
} }
@@ -888,23 +896,13 @@ final class FragmentManagerImpl extends FragmentManager {
case Fragment.STOPPED: case Fragment.STOPPED:
if (newState > Fragment.STOPPED) { if (newState > Fragment.STOPPED) {
if (DEBUG) Log.v(TAG, "moveto STARTED: " + f); if (DEBUG) Log.v(TAG, "moveto STARTED: " + f);
f.mCalled = false;
f.performStart(); f.performStart();
if (!f.mCalled) {
throw new SuperNotCalledException("Fragment " + f
+ " did not call through to super.onStart()");
}
} }
case Fragment.STARTED: case Fragment.STARTED:
if (newState > Fragment.STARTED) { if (newState > Fragment.STARTED) {
if (DEBUG) Log.v(TAG, "moveto RESUMED: " + f); if (DEBUG) Log.v(TAG, "moveto RESUMED: " + f);
f.mCalled = false;
f.mResumed = true; f.mResumed = true;
f.onResume(); f.performResume();
if (!f.mCalled) {
throw new SuperNotCalledException("Fragment " + f
+ " did not call through to super.onResume()");
}
// Get rid of this in case we saved it and never needed it. // Get rid of this in case we saved it and never needed it.
f.mSavedFragmentState = null; f.mSavedFragmentState = null;
f.mSavedViewState = null; f.mSavedViewState = null;
@@ -915,23 +913,13 @@ final class FragmentManagerImpl extends FragmentManager {
case Fragment.RESUMED: case Fragment.RESUMED:
if (newState < Fragment.RESUMED) { if (newState < Fragment.RESUMED) {
if (DEBUG) Log.v(TAG, "movefrom RESUMED: " + f); if (DEBUG) Log.v(TAG, "movefrom RESUMED: " + f);
f.mCalled = false; f.performPause();
f.onPause();
if (!f.mCalled) {
throw new SuperNotCalledException("Fragment " + f
+ " did not call through to super.onPause()");
}
f.mResumed = false; f.mResumed = false;
} }
case Fragment.STARTED: case Fragment.STARTED:
if (newState < Fragment.STARTED) { if (newState < Fragment.STARTED) {
if (DEBUG) Log.v(TAG, "movefrom STARTED: " + f); if (DEBUG) Log.v(TAG, "movefrom STARTED: " + f);
f.mCalled = false;
f.performStop(); f.performStop();
if (!f.mCalled) {
throw new SuperNotCalledException("Fragment " + f
+ " did not call through to super.onStop()");
}
} }
case Fragment.STOPPED: case Fragment.STOPPED:
case Fragment.ACTIVITY_CREATED: case Fragment.ACTIVITY_CREATED:
@@ -944,12 +932,7 @@ final class FragmentManagerImpl extends FragmentManager {
saveFragmentViewState(f); saveFragmentViewState(f);
} }
} }
f.mCalled = false;
f.performDestroyView(); f.performDestroyView();
if (!f.mCalled) {
throw new SuperNotCalledException("Fragment " + f
+ " did not call through to super.onDestroyView()");
}
if (f.mView != null && f.mContainer != null) { if (f.mView != null && f.mContainer != null) {
Animator anim = null; Animator anim = null;
if (mCurState > Fragment.INITIALIZING && !mDestroyed) { if (mCurState > Fragment.INITIALIZING && !mDestroyed) {
@@ -1008,12 +991,7 @@ final class FragmentManagerImpl extends FragmentManager {
} else { } else {
if (DEBUG) Log.v(TAG, "movefrom CREATED: " + f); if (DEBUG) Log.v(TAG, "movefrom CREATED: " + f);
if (!f.mRetaining) { if (!f.mRetaining) {
f.mCalled = false; f.performDestroy();
f.onDestroy();
if (!f.mCalled) {
throw new SuperNotCalledException("Fragment " + f
+ " did not call through to super.onDestroy()");
}
} }
f.mCalled = false; f.mCalled = false;
@@ -1027,6 +1005,7 @@ final class FragmentManagerImpl extends FragmentManager {
makeInactive(f); makeInactive(f);
} else { } else {
f.mActivity = null; f.mActivity = null;
f.mParentFragment = null;
f.mFragmentManager = null; f.mFragmentManager = null;
} }
} }
@@ -1050,11 +1029,11 @@ final class FragmentManagerImpl extends FragmentManager {
if (mActivity == null && newState != Fragment.INITIALIZING) { if (mActivity == null && newState != Fragment.INITIALIZING) {
throw new IllegalStateException("No activity"); throw new IllegalStateException("No activity");
} }
if (!always && mCurState == newState) { if (!always && mCurState == newState) {
return; return;
} }
mCurState = newState; mCurState = newState;
if (mActive != null) { if (mActive != null) {
boolean loadersRunning = false; boolean loadersRunning = false;
@@ -1099,11 +1078,11 @@ final class FragmentManagerImpl extends FragmentManager {
if (mActive == null) { if (mActive == null) {
mActive = new ArrayList<Fragment>(); mActive = new ArrayList<Fragment>();
} }
f.setIndex(mActive.size()); f.setIndex(mActive.size(), mParent);
mActive.add(f); mActive.add(f);
} else { } else {
f.setIndex(mAvailIndices.remove(mAvailIndices.size()-1)); f.setIndex(mAvailIndices.remove(mAvailIndices.size()-1), mParent);
mActive.set(f.mIndex, f); mActive.set(f.mIndex, f);
} }
if (DEBUG) Log.v(TAG, "Allocated fragment index " + f); if (DEBUG) Log.v(TAG, "Allocated fragment index " + f);
@@ -1120,7 +1099,7 @@ final class FragmentManagerImpl extends FragmentManager {
mAvailIndices = new ArrayList<Integer>(); mAvailIndices = new ArrayList<Integer>();
} }
mAvailIndices.add(f.mIndex); mAvailIndices.add(f.mIndex);
mActivity.invalidateFragmentIndex(f.mIndex); mActivity.invalidateFragment(f.mWho);
f.initState(); f.initState();
} }
@@ -1296,7 +1275,7 @@ final class FragmentManagerImpl extends FragmentManager {
if (mActive != null && who != null) { if (mActive != null && who != null) {
for (int i=mActive.size()-1; i>=0; i--) { for (int i=mActive.size()-1; i>=0; i--) {
Fragment f = mActive.get(i); Fragment f = mActive.get(i);
if (f != null && who.equals(f.mWho)) { if (f != null && (f=f.findFragmentByWho(who)) != null) {
return f; return f;
} }
} }
@@ -1566,7 +1545,7 @@ final class FragmentManagerImpl extends FragmentManager {
if (mStateBundle == null) { if (mStateBundle == null) {
mStateBundle = new Bundle(); mStateBundle = new Bundle();
} }
f.onSaveInstanceState(mStateBundle); f.performSaveInstanceState(mStateBundle);
if (!mStateBundle.isEmpty()) { if (!mStateBundle.isEmpty()) {
result = mStateBundle; result = mStateBundle;
mStateBundle = null; mStateBundle = null;
@@ -1735,7 +1714,7 @@ final class FragmentManagerImpl extends FragmentManager {
for (int i=0; i<fms.mActive.length; i++) { for (int i=0; i<fms.mActive.length; i++) {
FragmentState fs = fms.mActive[i]; FragmentState fs = fms.mActive[i];
if (fs != null) { if (fs != null) {
Fragment f = fs.instantiate(mActivity); Fragment f = fs.instantiate(mActivity, mParent);
if (DEBUG) Log.v(TAG, "restoreAllState: adding #" + i + ": " + f); if (DEBUG) Log.v(TAG, "restoreAllState: adding #" + i + ": " + f);
mActive.add(f); mActive.add(f);
// Now that the fragment is instantiated (or came from being // Now that the fragment is instantiated (or came from being
@@ -1803,9 +1782,11 @@ final class FragmentManagerImpl extends FragmentManager {
} }
} }
public void attachActivity(Activity activity) { public void attachActivity(Activity activity, FragmentContainer container, Fragment parent) {
if (mActivity != null) throw new IllegalStateException("Already attached"); if (mActivity != null) throw new IllegalStateException("Already attached");
mActivity = activity; mActivity = activity;
mContainer = container;
mParent = parent;
} }
public void noteStateNotSaved() { public void noteStateNotSaved() {
@@ -1840,11 +1821,17 @@ final class FragmentManagerImpl extends FragmentManager {
moveToState(Fragment.STOPPED, false); moveToState(Fragment.STOPPED, false);
} }
public void dispatchDestroyView() {
moveToState(Fragment.CREATED, false);
}
public void dispatchDestroy() { public void dispatchDestroy() {
mDestroyed = true; mDestroyed = true;
execPendingActions(); execPendingActions();
moveToState(Fragment.INITIALIZING, false); moveToState(Fragment.INITIALIZING, false);
mActivity = null; mActivity = null;
mContainer = null;
mParent = null;
} }
public void dispatchConfigurationChanged(Configuration newConfig) { public void dispatchConfigurationChanged(Configuration newConfig) {
@@ -1852,7 +1839,7 @@ final class FragmentManagerImpl extends FragmentManager {
for (int i=0; i<mAdded.size(); i++) { for (int i=0; i<mAdded.size(); i++) {
Fragment f = mAdded.get(i); Fragment f = mAdded.get(i);
if (f != null) { if (f != null) {
f.onConfigurationChanged(newConfig); f.performConfigurationChanged(newConfig);
} }
} }
} }
@@ -1863,7 +1850,7 @@ final class FragmentManagerImpl extends FragmentManager {
for (int i=0; i<mAdded.size(); i++) { for (int i=0; i<mAdded.size(); i++) {
Fragment f = mAdded.get(i); Fragment f = mAdded.get(i);
if (f != null) { if (f != null) {
f.onLowMemory(); f.performLowMemory();
} }
} }
} }
@@ -1874,7 +1861,7 @@ final class FragmentManagerImpl extends FragmentManager {
for (int i=0; i<mAdded.size(); i++) { for (int i=0; i<mAdded.size(); i++) {
Fragment f = mAdded.get(i); Fragment f = mAdded.get(i);
if (f != null) { if (f != null) {
f.onTrimMemory(level); f.performTrimMemory(level);
} }
} }
} }
@@ -1886,13 +1873,14 @@ final class FragmentManagerImpl extends FragmentManager {
if (mAdded != null) { if (mAdded != null) {
for (int i=0; i<mAdded.size(); i++) { for (int i=0; i<mAdded.size(); i++) {
Fragment f = mAdded.get(i); Fragment f = mAdded.get(i);
if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible) { if (f != null) {
show = true; if (f.performCreateOptionsMenu(menu, inflater)) {
f.onCreateOptionsMenu(menu, inflater); show = true;
if (newMenus == null) { if (newMenus == null) {
newMenus = new ArrayList<Fragment>(); newMenus = new ArrayList<Fragment>();
}
newMenus.add(f);
} }
newMenus.add(f);
} }
} }
} }
@@ -1916,9 +1904,10 @@ final class FragmentManagerImpl extends FragmentManager {
if (mAdded != null) { if (mAdded != null) {
for (int i=0; i<mAdded.size(); i++) { for (int i=0; i<mAdded.size(); i++) {
Fragment f = mAdded.get(i); Fragment f = mAdded.get(i);
if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible) { if (f != null) {
show = true; if (f.performPrepareOptionsMenu(menu)) {
f.onPrepareOptionsMenu(menu); show = true;
}
} }
} }
} }
@@ -1929,8 +1918,8 @@ final class FragmentManagerImpl extends FragmentManager {
if (mAdded != null) { if (mAdded != null) {
for (int i=0; i<mAdded.size(); i++) { for (int i=0; i<mAdded.size(); i++) {
Fragment f = mAdded.get(i); Fragment f = mAdded.get(i);
if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible) { if (f != null) {
if (f.onOptionsItemSelected(item)) { if (f.performOptionsItemSelected(item)) {
return true; return true;
} }
} }
@@ -1943,8 +1932,8 @@ final class FragmentManagerImpl extends FragmentManager {
if (mAdded != null) { if (mAdded != null) {
for (int i=0; i<mAdded.size(); i++) { for (int i=0; i<mAdded.size(); i++) {
Fragment f = mAdded.get(i); Fragment f = mAdded.get(i);
if (f != null && !f.mHidden) { if (f != null) {
if (f.onContextItemSelected(item)) { if (f.performContextItemSelected(item)) {
return true; return true;
} }
} }
@@ -1957,8 +1946,8 @@ final class FragmentManagerImpl extends FragmentManager {
if (mAdded != null) { if (mAdded != null) {
for (int i=0; i<mAdded.size(); i++) { for (int i=0; i<mAdded.size(); i++) {
Fragment f = mAdded.get(i); Fragment f = mAdded.get(i);
if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible) { if (f != null) {
f.onOptionsMenuClosed(menu); f.performOptionsMenuClosed(menu);
} }
} }
} }

View File

@@ -17,7 +17,6 @@
package android.app; package android.app;
import android.content.Loader; import android.content.Loader;
import android.content.Loader.OnLoadCanceledListener;
import android.os.Bundle; import android.os.Bundle;
import android.util.DebugUtils; import android.util.DebugUtils;
import android.util.Log; import android.util.Log;
@@ -213,6 +212,8 @@ class LoaderManagerImpl extends LoaderManager {
// previously run loader until the new loader's data is available. // previously run loader until the new loader's data is available.
final SparseArray<LoaderInfo> mInactiveLoaders = new SparseArray<LoaderInfo>(); final SparseArray<LoaderInfo> mInactiveLoaders = new SparseArray<LoaderInfo>();
final String mWho;
Activity mActivity; Activity mActivity;
boolean mStarted; boolean mStarted;
boolean mRetaining; boolean mRetaining;
@@ -529,7 +530,8 @@ class LoaderManagerImpl extends LoaderManager {
} }
} }
LoaderManagerImpl(Activity activity, boolean started) { LoaderManagerImpl(String who, Activity activity, boolean started) {
mWho = who;
mActivity = activity; mActivity = activity;
mStarted = started; mStarted = started;
} }