summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Powell <adamp@google.com>2011-10-26 10:22:16 -0700
committerAdam Powell <adamp@google.com>2011-10-27 15:54:51 -0700
commit635c60af623c73d2409f5729c0953638b5d6c497 (patch)
tree68764f2f1896dfe647f7a19a1bedf0bf55c7a564
parent6e03b22015bd834da1a5755e75d7468e5b3b13c5 (diff)
downloadframeworks_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.txt2
-rw-r--r--core/java/android/app/Fragment.java35
-rw-r--r--core/java/android/app/FragmentManager.java29
-rw-r--r--core/java/android/app/LoaderManager.java14
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;
+ }
}