diff options
-rw-r--r-- | api/current.txt | 4 | ||||
-rw-r--r-- | core/java/android/app/Fragment.java | 39 | ||||
-rw-r--r-- | core/java/android/app/FragmentManager.java | 38 |
3 files changed, 60 insertions, 21 deletions
diff --git a/api/current.txt b/api/current.txt index 4e41c29..cc7f0798 100644 --- a/api/current.txt +++ b/api/current.txt @@ -3235,6 +3235,7 @@ package android.app { method public final android.app.Fragment getTargetFragment(); method public final int getTargetRequestCode(); method public final java.lang.CharSequence getText(int); + method public boolean getUserVisibleHint(); method public android.view.View getView(); method public final int hashCode(); method public static android.app.Fragment instantiate(android.content.Context, java.lang.String); @@ -3245,7 +3246,6 @@ 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); @@ -3281,8 +3281,8 @@ 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 setUserVisibleHint(boolean); method public void startActivity(android.content.Intent); method public void startActivityForResult(android.content.Intent, int); method public void unregisterForContextMenu(android.view.View); diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java index 9b01b7f..473a2d1 100644 --- a/core/java/android/app/Fragment.java +++ b/core/java/android/app/Fragment.java @@ -458,6 +458,9 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene // have been started and their loaders are finished. boolean mDeferStart; + // Hint provided by the app that this fragment is currently visible to the user. + boolean mUserVisibleHint = true; + LoaderManagerImpl mLoaderManager; boolean mLoadersStarted; boolean mCheckedForLoaderManager; @@ -915,31 +918,32 @@ 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. + * Set a hint to the system about whether this fragment's UI is currently visible + * to the user. This hint defaults to true and is persistent across fragment instance + * state save and restore. * - * <p>This option is not sticky across fragment starts; after a deferred start - * completes this option will be set to false.</p> + * <p>An app may set this to false to indicate that the fragment's UI is + * scrolled out of visibility or is otherwise not directly visible to the user. + * This may be used by the system to prioritize operations such as fragment lifecycle updates + * or loader ordering behavior.</p> * - * @param deferResume true if this fragment can defer its resume until after others + * @param isVisibleToUser true if this fragment's UI is currently visible to the user (default), + * false if it is not. */ - public void setStartDeferred(boolean deferResume) { - if (mDeferStart && !deferResume) { + public void setUserVisibleHint(boolean isVisibleToUser) { + if (!mUserVisibleHint && isVisibleToUser && mState < STARTED) { mFragmentManager.performPendingDeferredStart(this); } - mDeferStart = deferResume; + mUserVisibleHint = isVisibleToUser; + mDeferStart = !isVisibleToUser; } /** - * 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. + * @return The current value of the user-visible hint on this fragment. + * @see #setUserVisibleHint(boolean) */ - public boolean isStartDeferred() { - return mDeferStart; + public boolean getUserVisibleHint() { + return mUserVisibleHint; } /** @@ -1477,7 +1481,8 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene writer.print(" mMenuVisible="); writer.print(mMenuVisible); writer.print(" mHasMenu="); writer.println(mHasMenu); writer.print(prefix); writer.print("mRetainInstance="); writer.print(mRetainInstance); - writer.print(" mRetaining="); writer.println(mRetaining); + writer.print(" mRetaining="); writer.print(mRetaining); + writer.print(" mUserVisibleHint="); writer.println(mUserVisibleHint); if (mFragmentManager != null) { writer.print(prefix); writer.print("mFragmentManager="); writer.println(mFragmentManager); diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java index c4ba778..a8c9cba 100644 --- a/core/java/android/app/FragmentManager.java +++ b/core/java/android/app/FragmentManager.java @@ -382,6 +382,7 @@ final class FragmentManagerImpl extends FragmentManager { static final String TARGET_REQUEST_CODE_STATE_TAG = "android:target_req_state"; static final String TARGET_STATE_TAG = "android:target_state"; static final String VIEW_STATE_TAG = "android:view_state"; + static final String USER_VISIBLE_HINT_TAG = "android:user_visible_hint"; ArrayList<Runnable> mPendingActions; Runnable[] mTmpActions; @@ -406,6 +407,7 @@ final class FragmentManagerImpl extends FragmentManager { boolean mStateSaved; boolean mDestroyed; String mNoTransactionsBecause; + boolean mHavePendingDeferredStart; // Temporary vars for state save and restore. Bundle mStateBundle = null; @@ -711,6 +713,11 @@ final class FragmentManagerImpl extends FragmentManager { public void performPendingDeferredStart(Fragment f) { if (f.mDeferStart) { + if (mExecutingActions) { + // Wait until we're done executing our pending transactions + mHavePendingDeferredStart = true; + return; + } f.mDeferStart = false; moveToState(f, mCurState, 0, 0); } @@ -757,6 +764,14 @@ final class FragmentManagerImpl extends FragmentManager { f.mTargetRequestCode = f.mSavedFragmentState.getInt( FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG, 0); } + f.mUserVisibleHint = f.mSavedFragmentState.getBoolean( + FragmentManagerImpl.USER_VISIBLE_HINT_TAG, true); + if (!f.mUserVisibleHint) { + f.mDeferStart = true; + if (newState > Fragment.STOPPED) { + newState = Fragment.STOPPED; + } + } } f.mActivity = mActivity; f.mFragmentManager = mActivity.mFragments; @@ -1343,7 +1358,7 @@ final class FragmentManagerImpl extends FragmentManager { synchronized (this) { if (mPendingActions == null || mPendingActions.size() == 0) { - return didSomething; + break; } numActions = mPendingActions.size(); @@ -1363,8 +1378,23 @@ final class FragmentManagerImpl extends FragmentManager { mExecutingActions = false; didSomething = true; } + + if (mHavePendingDeferredStart) { + boolean loadersRunning = false; + for (int i=0; i<mActive.size(); i++) { + Fragment f = mActive.get(i); + if (f != null && f.mLoaderManager != null) { + loadersRunning |= f.mLoaderManager.hasRunningLoaders(); + } + } + if (!loadersRunning) { + mHavePendingDeferredStart = false; + startPendingDeferredFragments(); + } + } + return didSomething; } - + void reportBackStackChanged() { if (mBackStackChangeListeners != null) { for (int i=0; i<mBackStackChangeListeners.size(); i++) { @@ -1500,6 +1530,10 @@ final class FragmentManagerImpl extends FragmentManager { result.putSparseParcelableArray( FragmentManagerImpl.VIEW_STATE_TAG, f.mSavedViewState); } + if (!f.mUserVisibleHint) { + // Only add this if it's not the default value + result.putBoolean(FragmentManagerImpl.USER_VISIBLE_HINT_TAG, f.mUserVisibleHint); + } return result; } |