diff options
Diffstat (limited to 'core/java')
| -rw-r--r-- | core/java/android/app/Activity.java | 41 | ||||
| -rw-r--r-- | core/java/android/app/ActivityThread.java | 5 | ||||
| -rw-r--r-- | core/java/android/app/Fragment.java | 32 | ||||
| -rw-r--r-- | core/java/android/app/FragmentManager.java | 18 | ||||
| -rw-r--r-- | core/java/android/app/LoaderManager.java | 62 |
5 files changed, 119 insertions, 39 deletions
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index f08d88d..378a8bd 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -645,11 +645,13 @@ public class Activity extends ContextThemeWrapper Activity mParent; boolean mCalled; boolean mCheckedForLoaderManager; - boolean mStarted; + boolean mLoadersStarted; private boolean mResumed; private boolean mStopped; boolean mFinished; boolean mStartedActivity; + /** true if the activity is going through a transient pause */ + /*package*/ boolean mTemporaryPause = false; /** true if the activity is being destroyed in order to recreate it with a new configuration */ /*package*/ boolean mChangingConfigurations = false; /*package*/ int mConfigChangeFlags; @@ -768,7 +770,7 @@ public class Activity extends ContextThemeWrapper return mLoaderManager; } mCheckedForLoaderManager = true; - mLoaderManager = getLoaderManager(-1, mStarted, true); + mLoaderManager = getLoaderManager(-1, mLoadersStarted, true); return mLoaderManager; } @@ -777,9 +779,13 @@ public class Activity extends ContextThemeWrapper mAllLoaderManagers = new SparseArray<LoaderManagerImpl>(); } LoaderManagerImpl lm = mAllLoaderManagers.get(index); - if (lm == null && create) { - lm = new LoaderManagerImpl(started); - mAllLoaderManagers.put(index, lm); + if (lm == null) { + if (create) { + lm = new LoaderManagerImpl(this, started); + mAllLoaderManagers.put(index, lm); + } + } else { + lm.updateActivity(this); } return lm; } @@ -979,13 +985,16 @@ public class Activity extends ContextThemeWrapper */ protected void onStart() { mCalled = true; - mStarted = true; - if (mLoaderManager != null) { - mLoaderManager.doStart(); - } else if (!mCheckedForLoaderManager) { - mLoaderManager = getLoaderManager(-1, mStarted, false); + + if (!mLoadersStarted) { + mLoadersStarted = true; + if (mLoaderManager != null) { + mLoaderManager.doStart(); + } else if (!mCheckedForLoaderManager) { + mLoaderManager = getLoaderManager(-1, mLoadersStarted, false); + } + mCheckedForLoaderManager = true; } - mCheckedForLoaderManager = true; } /** @@ -4249,7 +4258,7 @@ public class Activity extends ContextThemeWrapper } final void performStart() { - mFragments.mStateSaved = false; + mFragments.noteStateNotSaved(); mCalled = false; mFragments.execPendingActions(); mInstrumentation.callActivityOnStart(this); @@ -4267,7 +4276,7 @@ public class Activity extends ContextThemeWrapper } final void performRestart() { - mFragments.mStateSaved = false; + mFragments.noteStateNotSaved(); synchronized (mManagedCursors) { final int N = mManagedCursors.size(); @@ -4347,8 +4356,8 @@ public class Activity extends ContextThemeWrapper } final void performStop() { - if (mStarted) { - mStarted = false; + if (mLoadersStarted) { + mLoadersStarted = false; if (mLoaderManager != null) { if (!mChangingConfigurations) { mLoaderManager.doStop(); @@ -4407,7 +4416,7 @@ public class Activity extends ContextThemeWrapper if (Config.LOGV) Log.v( TAG, "Dispatching result: who=" + who + ", reqCode=" + requestCode + ", resCode=" + resultCode + ", data=" + data); - mFragments.mStateSaved = false; + mFragments.noteStateNotSaved(); if (who == null) { onActivityResult(requestCode, resultCode, data); } else { diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index f3f7ee7..2abe822 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -1757,6 +1757,7 @@ public final class ActivityThread { for (int i=0; i<N; i++) { Intent intent = intents.get(i); intent.setExtrasClassLoader(r.activity.getClassLoader()); + r.activity.mFragments.noteStateNotSaved(); mInstrumentation.callActivityOnNewIntent(r.activity, intent); } } @@ -1767,11 +1768,13 @@ public final class ActivityThread { if (r != null) { final boolean resumed = !r.paused; if (resumed) { + r.activity.mTemporaryPause = true; mInstrumentation.callActivityOnPause(r.activity); } deliverNewIntents(r, intents); if (resumed) { mInstrumentation.callActivityOnResume(r.activity); + r.activity.mTemporaryPause = false; } } } @@ -2594,6 +2597,7 @@ public final class ActivityThread { try { // Now we are idle. r.activity.mCalled = false; + r.activity.mTemporaryPause = true; mInstrumentation.callActivityOnPause(r.activity); if (!r.activity.mCalled) { throw new SuperNotCalledException( @@ -2614,6 +2618,7 @@ public final class ActivityThread { deliverResults(r, res.results); if (resumed) { mInstrumentation.callActivityOnResume(r.activity); + r.activity.mTemporaryPause = false; } } } diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java index 12bf7e5..3ec0912 100644 --- a/core/java/android/app/Fragment.java +++ b/core/java/android/app/Fragment.java @@ -403,7 +403,7 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener View mView; LoaderManagerImpl mLoaderManager; - boolean mStarted; + boolean mLoadersStarted; boolean mCheckedForLoaderManager; /** @@ -728,7 +728,7 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener return mLoaderManager; } mCheckedForLoaderManager = true; - mLoaderManager = mActivity.getLoaderManager(mIndex, mStarted, true); + mLoaderManager = mActivity.getLoaderManager(mIndex, mLoadersStarted, true); return mLoaderManager; } @@ -880,13 +880,16 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener */ public void onStart() { mCalled = true; - mStarted = true; - if (!mCheckedForLoaderManager) { - mCheckedForLoaderManager = true; - mLoaderManager = mActivity.getLoaderManager(mIndex, mStarted, false); - } - if (mLoaderManager != null) { - mLoaderManager.doStart(); + + if (!mLoadersStarted) { + mLoadersStarted = true; + if (!mCheckedForLoaderManager) { + mCheckedForLoaderManager = true; + mLoaderManager = mActivity.getLoaderManager(mIndex, mLoadersStarted, false); + } + if (mLoaderManager != null) { + mLoaderManager.doStart(); + } } } @@ -971,7 +974,7 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener // + " mLoaderManager=" + mLoaderManager); if (!mCheckedForLoaderManager) { mCheckedForLoaderManager = true; - mLoaderManager = mActivity.getLoaderManager(mIndex, mStarted, false); + mLoaderManager = mActivity.getLoaderManager(mIndex, mLoadersStarted, false); } if (mLoaderManager != null) { mLoaderManager.doDestroy(); @@ -1182,7 +1185,7 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener } if (mLoaderManager != null) { writer.print(prefix); writer.print("mLoaderManager="); writer.print(mLoaderManager); - writer.print(" mStarted="); writer.print(mStarted); + writer.print(" mLoadersStarted="); writer.print(mLoadersStarted); writer.print(" mCheckedForLoaderManager="); writer.println(mCheckedForLoaderManager); } @@ -1190,11 +1193,12 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener void performStop() { onStop(); - if (mStarted) { - mStarted = false; + + if (mLoadersStarted) { + mLoadersStarted = false; if (!mCheckedForLoaderManager) { mCheckedForLoaderManager = true; - mLoaderManager = mActivity.getLoaderManager(mIndex, mStarted, false); + mLoaderManager = mActivity.getLoaderManager(mIndex, mLoadersStarted, false); } if (mLoaderManager != null) { if (mActivity == null || !mActivity.mChangingConfigurations) { diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java index 37e7253..d9a6171 100644 --- a/core/java/android/app/FragmentManager.java +++ b/core/java/android/app/FragmentManager.java @@ -86,6 +86,15 @@ public interface FragmentManager { /** * Start a series of edit operations on the Fragments associated with * this FragmentManager. + * + * <p>Note: A fragment transaction can only be created/committed prior + * to an activity saving its state. If you try to commit a transaction + * after {@link Activity#onSaveInstanceState Activity.onSaveInstanceState()} + * (and prior to a following {@link Activity#onStart Activity.onStart} + * or {@link Activity#onResume Activity.onResume()}, you will get an error. + * This is because the framework takes care of saving your current fragments + * in the state, and if changes are made after the state is saved then they + * will be lost.</p> */ public FragmentTransaction openTransaction(); @@ -271,6 +280,7 @@ final class FragmentManagerImpl implements FragmentManager { boolean mNeedMenuInvalidate; boolean mStateSaved; + String mNoTransactionsBecause; // Temporary vars for state save and restore. Bundle mStateBundle = null; @@ -843,6 +853,10 @@ final class FragmentManagerImpl implements FragmentManager { throw new IllegalStateException( "Can not perform this action after onSaveInstanceState"); } + if (mNoTransactionsBecause != null) { + throw new IllegalStateException( + "Can not perform this action inside of " + mNoTransactionsBecause); + } synchronized (this) { if (mPendingActions == null) { mPendingActions = new ArrayList<Runnable>(); @@ -1271,6 +1285,10 @@ final class FragmentManagerImpl implements FragmentManager { mActivity = activity; } + public void noteStateNotSaved() { + mStateSaved = false; + } + public void dispatchCreate() { mStateSaved = false; moveToState(Fragment.CREATED, false); diff --git a/core/java/android/app/LoaderManager.java b/core/java/android/app/LoaderManager.java index 28abcaa..4d4ea9a 100644 --- a/core/java/android/app/LoaderManager.java +++ b/core/java/android/app/LoaderManager.java @@ -40,7 +40,12 @@ public interface LoaderManager { public Loader<D> onCreateLoader(int id, Bundle args); /** - * Called when a previously created loader has finished its load. + * Called when a previously created loader has finished its load. Note + * that normally an application is <em>not</em> allowed to commit fragment + * transactions while in this call, since it can happen after an + * activity's state is saved. See {@link FragmentManager#openTransaction() + * FragmentManager.openTransaction()} for further discussion on this. + * * @param loader The Loader that has finished. * @param data The data generated by the Loader. */ @@ -102,6 +107,7 @@ class LoaderManagerImpl implements LoaderManager { // previously run loader until the new loader's data is available. final SparseArray<LoaderInfo> mInactiveLoaders = new SparseArray<LoaderInfo>(); + Activity mActivity; boolean mStarted; boolean mRetaining; boolean mRetainingStarted; @@ -172,12 +178,12 @@ class LoaderManagerImpl implements LoaderManager { stop(); } } - if (mStarted && mData != null && mCallbacks != null) { + if (mStarted && mData != null) { // This loader was retained, and now at the point of // finishing the retain we find we remain started, have // our data, and the owner has a new callback... so // let's deliver the data now. - mCallbacks.onLoadFinished(mLoader, mData); + callOnLoadFinished(mLoader, mData); } } } @@ -219,9 +225,7 @@ class LoaderManagerImpl implements LoaderManager { // Notify of the new data so the app can switch out the old data before // we try to destroy it. mData = data; - if (mCallbacks != null) { - mCallbacks.onLoadFinished(loader, data); - } + callOnLoadFinished(loader, data); if (DEBUG) Log.v(TAG, "onLoadFinished returned: " + this); @@ -236,6 +240,23 @@ class LoaderManagerImpl implements LoaderManager { } } + void callOnLoadFinished(Loader<Object> loader, Object data) { + if (mCallbacks != null) { + String lastBecause = null; + if (mActivity != null) { + lastBecause = mActivity.mFragments.mNoTransactionsBecause; + mActivity.mFragments.mNoTransactionsBecause = "onLoadFinished"; + } + try { + mCallbacks.onLoadFinished(loader, data); + } finally { + if (mActivity != null) { + mActivity.mFragments.mNoTransactionsBecause = lastBecause; + } + } + } + } + @Override public String toString() { StringBuilder sb = new StringBuilder(64); @@ -252,10 +273,15 @@ class LoaderManagerImpl implements LoaderManager { } } - LoaderManagerImpl(boolean started) { + LoaderManagerImpl(Activity activity, boolean started) { + mActivity = activity; mStarted = started; } + void updateActivity(Activity activity) { + mActivity = activity; + } + private LoaderInfo createLoader(int id, Bundle args, LoaderManager.LoaderCallbacks<Object> callback) { LoaderInfo info = new LoaderInfo(id, args, (LoaderManager.LoaderCallbacks<Object>)callback); @@ -286,7 +312,7 @@ class LoaderManagerImpl implements LoaderManager { if (info.mData != null && mStarted) { // If the loader has already generated its data, report it now. - info.mCallbacks.onLoadFinished(info.mLoader, info.mData); + info.callOnLoadFinished(info.mLoader, info.mData); } return (Loader<D>)info.mLoader; @@ -348,7 +374,13 @@ class LoaderManagerImpl implements LoaderManager { void doStart() { if (DEBUG) Log.v(TAG, "Starting: " + this); - + if (mStarted) { + RuntimeException e = new RuntimeException("here"); + e.fillInStackTrace(); + Log.w(TAG, "Called doStart when already started: " + this, e); + return; + } + // Call out to sub classes so they can start their loaders // Let the existing loaders know that we want to be notified when a load is complete for (int i = mLoaders.size()-1; i >= 0; i--) { @@ -359,6 +391,12 @@ class LoaderManagerImpl implements LoaderManager { void doStop() { if (DEBUG) Log.v(TAG, "Stopping: " + this); + if (!mStarted) { + RuntimeException e = new RuntimeException("here"); + e.fillInStackTrace(); + Log.w(TAG, "Called doStop when not started: " + this, e); + return; + } for (int i = mLoaders.size()-1; i >= 0; i--) { mLoaders.valueAt(i).stop(); @@ -368,6 +406,12 @@ class LoaderManagerImpl implements LoaderManager { void doRetain() { if (DEBUG) Log.v(TAG, "Retaining: " + this); + if (!mStarted) { + RuntimeException e = new RuntimeException("here"); + e.fillInStackTrace(); + Log.w(TAG, "Called doRetain when not started: " + this, e); + return; + } mRetaining = true; mStarted = false; |
