diff options
author | Adam Powell <adamp@google.com> | 2011-10-26 10:22:16 -0700 |
---|---|---|
committer | Adam Powell <adamp@google.com> | 2011-10-27 15:54:51 -0700 |
commit | 635c60af623c73d2409f5729c0953638b5d6c497 (patch) | |
tree | 68764f2f1896dfe647f7a19a1bedf0bf55c7a564 | |
parent | 6e03b22015bd834da1a5755e75d7468e5b3b13c5 (diff) | |
download | frameworks_base-635c60af623c73d2409f5729c0953638b5d6c497.zip frameworks_base-635c60af623c73d2409f5729c0953638b5d6c497.tar.gz frameworks_base-635c60af623c73d2409f5729c0953638b5d6c497.tar.bz2 |
Add API for deferring fragment start.
Fragments now have the setDeferStart method to signal that a fragment
has lower priority than others. Deferred start fragments will not
always be started immediately; they will be started once any loaders
have finished servicing any outstanding requests. This is useful if
any attached fragments are not immediately visible and can wait to
start until later.
Disabling deferStart on a fragment that is waiting for a deferred
start will start it immediately. Start.
Change-Id: Ia1f004877ca5e88d4f10147d21c7e2e97f141c34
-rw-r--r-- | api/current.txt | 2 | ||||
-rw-r--r-- | core/java/android/app/Fragment.java | 35 | ||||
-rw-r--r-- | core/java/android/app/FragmentManager.java | 29 | ||||
-rw-r--r-- | core/java/android/app/LoaderManager.java | 14 |
4 files changed, 78 insertions, 2 deletions
diff --git a/api/current.txt b/api/current.txt index b30f7a6..20791e3 100644 --- a/api/current.txt +++ b/api/current.txt @@ -3245,6 +3245,7 @@ package android.app { method public final boolean isInLayout(); method public final boolean isRemoving(); method public final boolean isResumed(); + method public boolean isStartDeferred(); method public final boolean isVisible(); method public void onActivityCreated(android.os.Bundle); method public void onActivityResult(int, int, android.content.Intent); @@ -3280,6 +3281,7 @@ package android.app { method public void setInitialSavedState(android.app.Fragment.SavedState); method public void setMenuVisibility(boolean); method public void setRetainInstance(boolean); + method public void setStartDeferred(boolean); method public void setTargetFragment(android.app.Fragment, int); method public void startActivity(android.content.Intent); method public void startActivityForResult(android.content.Intent, int); diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java index d423d98..9b01b7f 100644 --- a/core/java/android/app/Fragment.java +++ b/core/java/android/app/Fragment.java @@ -339,6 +339,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene private static final HashMap<String, Class<?>> sClassMap = new HashMap<String, Class<?>>(); + static final int INVALID_STATE = -1; // Invalid state used as a null value. 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. @@ -403,7 +404,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene // The fragment manager we are associated with. Set as soon as the // fragment is used in a transaction; cleared after it has been removed // from all transactions. - FragmentManager mFragmentManager; + FragmentManagerImpl mFragmentManager; // Activity this fragment is attached to. Activity mActivity; @@ -453,6 +454,10 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene // The View generated for this fragment. View mView; + // Whether this fragment should defer starting until after other fragments + // have been started and their loaders are finished. + boolean mDeferStart; + LoaderManagerImpl mLoaderManager; boolean mLoadersStarted; boolean mCheckedForLoaderManager; @@ -910,6 +915,34 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene } /** + * Set whether this fragment should enter the started state as normal or if + * start should be deferred until a system-determined convenient time, such + * as after any loaders have completed their work. + * + * <p>This option is not sticky across fragment starts; after a deferred start + * completes this option will be set to false.</p> + * + * @param deferResume true if this fragment can defer its resume until after others + */ + public void setStartDeferred(boolean deferResume) { + if (mDeferStart && !deferResume) { + mFragmentManager.performPendingDeferredStart(this); + } + mDeferStart = deferResume; + } + + /** + * Returns true if this fragment's move to the started state has been deferred. + * If this returns true it will be started once other fragments' loaders + * have finished running. + * + * @return true if this fragment's start has been deferred. + */ + public boolean isStartDeferred() { + return mDeferStart; + } + + /** * Return the LoaderManager for this fragment, creating it if needed. */ public LoaderManager getLoaderManager() { diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java index 3da4f29..58cd27c 100644 --- a/core/java/android/app/FragmentManager.java +++ b/core/java/android/app/FragmentManager.java @@ -709,6 +709,13 @@ final class FragmentManagerImpl extends FragmentManager { return AnimatorInflater.loadAnimator(mActivity, anim); } + public void performPendingDeferredStart(Fragment f) { + if (f.mDeferStart) { + f.mDeferStart = false; + moveToState(f, mCurState, 0, 0); + } + } + void moveToState(Fragment f, int newState, int transit, int transitionStyle) { // Fragments that are not currently added will sit in the onCreate() state. if (!f.mAdded && newState > Fragment.CREATED) { @@ -718,7 +725,10 @@ final class FragmentManagerImpl extends FragmentManager { // While removing a fragment, we can't change it to a higher state. newState = f.mState; } - + // Defer start if requested; don't allow it to move to STARTED or higher. + if (f.mDeferStart && newState > Fragment.STOPPED) { + newState = Fragment.STOPPED; + } if (f.mState < newState) { // For fragments that are created from a layout, when restoring from // state we don't want to allow them to be created until they are @@ -992,13 +1002,21 @@ final class FragmentManagerImpl extends FragmentManager { mCurState = newState; if (mActive != null) { + boolean loadersRunning = false; for (int i=0; i<mActive.size(); i++) { Fragment f = mActive.get(i); if (f != null) { moveToState(f, newState, transit, transitStyle); + if (f.mLoaderManager != null) { + loadersRunning |= f.mLoaderManager.hasRunningLoaders(); + } } } + if (!loadersRunning) { + startPendingDeferredFragments(); + } + if (mNeedMenuInvalidate && mActivity != null && mCurState == Fragment.RESUMED) { mActivity.invalidateOptionsMenu(); mNeedMenuInvalidate = false; @@ -1006,6 +1024,15 @@ final class FragmentManagerImpl extends FragmentManager { } } + void startPendingDeferredFragments() { + for (int i=0; i<mActive.size(); i++) { + Fragment f = mActive.get(i); + if (f != null) { + performPendingDeferredStart(f); + } + } + } + void makeActive(Fragment f) { if (f.mIndex >= 0) { return; diff --git a/core/java/android/app/LoaderManager.java b/core/java/android/app/LoaderManager.java index 89e9ddd..aef0c6f 100644 --- a/core/java/android/app/LoaderManager.java +++ b/core/java/android/app/LoaderManager.java @@ -418,6 +418,10 @@ class LoaderManagerImpl extends LoaderManager { info.destroy(); mInactiveLoaders.remove(mId); } + + if (!hasRunningLoaders() && mActivity != null) { + mActivity.mFragments.startPendingDeferredFragments(); + } } void callOnLoadFinished(Loader<Object> loader, Object data) { @@ -820,4 +824,14 @@ class LoaderManagerImpl extends LoaderManager { } } } + + public boolean hasRunningLoaders() { + boolean loadersRunning = false; + final int count = mLoaders.size(); + for (int i = 0; i < count; i++) { + final LoaderInfo li = mLoaders.valueAt(i); + loadersRunning |= li.mStarted && !li.mDeliveredData; + } + return loadersRunning; + } } |