From cbade7f4d3ed06636cdf0f2e2317a9e49b46852a Mon Sep 17 00:00:00 2001 From: Adam Powell Date: Fri, 15 Apr 2016 11:14:37 -0700 Subject: [PATCH] Retain loaders through stopped config changes Framework edition Previously we would throw away any stopped LoaderManagers when we went to retain instances to pass along as nonConfigurationInstances during config changes or similar activity restarts. This causes loaders to do more work than they need to when a calling activity starts a new activity on top, a config change happens (e.g. screen rotation) and then the top activity is finished, restarting the caller in a new configuration. The loaders would go through onReset unnecessarily, potentially throwing away data to be reloaded again after the config change completes. Instead of throwing away stopped LoaderManagers in this case, restart them and retain them across the config change so they can resume where they left off. Bug 27176186 Change-Id: Ia52c6448d2ad41dcb25d493770d9ffae20a19d2a --- core/java/android/app/Activity.java | 8 ++++++++ core/java/android/app/FragmentHostCallback.java | 11 +++++++++-- core/java/android/app/FragmentManager.java | 2 +- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index f7884a742b038..cc76854adca94 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -2098,7 +2098,15 @@ public class Activity extends ContextThemeWrapper Object activity = onRetainNonConfigurationInstance(); HashMap children = onRetainNonConfigurationChildInstances(); FragmentManagerNonConfig fragments = mFragments.retainNestedNonConfig(); + + // We're already stopped but we've been asked to retain. + // Our fragments are taken care of but we need to mark the loaders for retention. + // In order to do this correctly we need to restart the loaders first before + // handing them off to the next activity. + mFragments.doLoaderStart(); + mFragments.doLoaderStop(true); ArrayMap loaders = mFragments.retainLoaderNonConfig(); + if (activity == null && children == null && fragments == null && loaders == null && mVoiceInteractor == null) { return null; diff --git a/core/java/android/app/FragmentHostCallback.java b/core/java/android/app/FragmentHostCallback.java index cf6b1147aba04..e1d713626e2e1 100644 --- a/core/java/android/app/FragmentHostCallback.java +++ b/core/java/android/app/FragmentHostCallback.java @@ -308,15 +308,22 @@ public abstract class FragmentHostCallback extends FragmentContainer { ArrayMap retainLoaderNonConfig() { boolean retainLoaders = false; if (mAllLoaderManagers != null) { - // prune out any loader managers that were already stopped and so - // have nothing useful to retain. + // Restart any loader managers that were already stopped so that they + // will be ready to retain final int N = mAllLoaderManagers.size(); LoaderManagerImpl loaders[] = new LoaderManagerImpl[N]; for (int i=N-1; i>=0; i--) { loaders[i] = (LoaderManagerImpl) mAllLoaderManagers.valueAt(i); } + final boolean doRetainLoaders = getRetainLoaders(); for (int i=0; i