Merge "Add API for deferring fragment start." into ics-mr1

This commit is contained in:
Adam Powell
2011-10-28 10:43:33 -07:00
committed by Android (Google) Code Review
4 changed files with 78 additions and 2 deletions

View File

@@ -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);

View File

@@ -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;
@@ -909,6 +914,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.
*/

View File

@@ -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;

View File

@@ -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;
}
}