summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/Activity.java22
-rw-r--r--core/java/android/app/Fragment.java19
-rw-r--r--core/java/android/app/FragmentManager.java10
-rw-r--r--core/java/android/app/LoaderManager.java91
4 files changed, 117 insertions, 25 deletions
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index ee91318..c55c07f 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -635,6 +635,7 @@ public class Activity extends ContextThemeWrapper
/*package*/ ActivityThread mMainThread;
Activity mParent;
boolean mCalled;
+ boolean mCheckedForLoaderManager;
boolean mStarted;
private boolean mResumed;
private boolean mStopped;
@@ -774,16 +775,17 @@ public class Activity extends ContextThemeWrapper
if (mLoaderManager != null) {
return mLoaderManager;
}
- mLoaderManager = getLoaderManager(-1, mStarted);
+ mCheckedForLoaderManager = true;
+ mLoaderManager = getLoaderManager(-1, mStarted, true);
return mLoaderManager;
}
- LoaderManagerImpl getLoaderManager(int index, boolean started) {
+ LoaderManagerImpl getLoaderManager(int index, boolean started, boolean create) {
if (mAllLoaderManagers == null) {
mAllLoaderManagers = new SparseArray<LoaderManagerImpl>();
}
LoaderManagerImpl lm = mAllLoaderManagers.get(index);
- if (lm == null) {
+ if (lm == null && create) {
lm = new LoaderManagerImpl(started);
mAllLoaderManagers.put(index, lm);
}
@@ -992,7 +994,10 @@ public class Activity extends ContextThemeWrapper
mStarted = true;
if (mLoaderManager != null) {
mLoaderManager.doStart();
+ } else if (!mCheckedForLoaderManager) {
+ mLoaderManager = getLoaderManager(-1, mStarted, false);
}
+ mCheckedForLoaderManager = true;
}
/**
@@ -1550,13 +1555,14 @@ public class Activity extends ContextThemeWrapper
ArrayList<Fragment> fragments = mFragments.retainNonConfig();
boolean retainLoaders = false;
if (mAllLoaderManagers != null) {
- // prune out any loader managers that were already stopped, so
+ // prune out any loader managers that were already stopped and so
// have nothing useful to retain.
for (int i=mAllLoaderManagers.size()-1; i>=0; i--) {
LoaderManagerImpl lm = mAllLoaderManagers.valueAt(i);
if (lm.mRetaining) {
retainLoaders = true;
} else {
+ lm.doDestroy();
mAllLoaderManagers.removeAt(i);
}
}
@@ -1586,7 +1592,12 @@ public class Activity extends ContextThemeWrapper
}
void invalidateFragmentIndex(int index) {
+ //Log.v(TAG, "invalidateFragmentIndex: index=" + index);
if (mAllLoaderManagers != null) {
+ LoaderManagerImpl lm = mAllLoaderManagers.get(index);
+ if (lm != null) {
+ lm.doDestroy();
+ }
mAllLoaderManagers.remove(index);
}
}
@@ -4289,6 +4300,9 @@ public class Activity extends ContextThemeWrapper
final void performDestroy() {
mFragments.dispatchDestroy();
onDestroy();
+ if (mLoaderManager != null) {
+ mLoaderManager.doDestroy();
+ }
}
final boolean isResumed() {
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 26cd9de..0bb200c 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -24,6 +24,7 @@ import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
+import android.util.Log;
import android.util.SparseArray;
import android.view.ContextMenu;
import android.view.LayoutInflater;
@@ -216,6 +217,7 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener
LoaderManagerImpl mLoaderManager;
boolean mStarted;
+ boolean mCheckedForLoaderManager;
/**
* Default constructor. <strong>Every</string> fragment must have an
@@ -426,7 +428,8 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener
if (mLoaderManager != null) {
return mLoaderManager;
}
- mLoaderManager = mActivity.getLoaderManager(mIndex, mStarted);
+ mCheckedForLoaderManager = true;
+ mLoaderManager = mActivity.getLoaderManager(mIndex, mStarted, true);
return mLoaderManager;
}
@@ -567,6 +570,10 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener
public void onStart() {
mCalled = true;
mStarted = true;
+ if (!mCheckedForLoaderManager) {
+ mCheckedForLoaderManager = true;
+ mLoaderManager = mActivity.getLoaderManager(mIndex, mStarted, false);
+ }
if (mLoaderManager != null) {
mLoaderManager.doStart();
}
@@ -628,6 +635,12 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener
*/
public void onDestroy() {
mCalled = true;
+ //Log.v("foo", "onDestroy: mCheckedForLoaderManager=" + mCheckedForLoaderManager
+ // + " mLoaderManager=" + mLoaderManager);
+ if (!mCheckedForLoaderManager) {
+ mCheckedForLoaderManager = true;
+ mLoaderManager = mActivity.getLoaderManager(mIndex, mStarted, false);
+ }
if (mLoaderManager != null) {
mLoaderManager.doDestroy();
}
@@ -777,6 +790,10 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener
onStop();
if (mStarted) {
mStarted = false;
+ if (!mCheckedForLoaderManager) {
+ mCheckedForLoaderManager = true;
+ mLoaderManager = mActivity.getLoaderManager(mIndex, mStarted, false);
+ }
if (mLoaderManager != null) {
if (mActivity == null || !mActivity.mChangingConfigurations) {
mLoaderManager.doStop();
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 2054e2a..35b4610 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -385,12 +385,12 @@ public class FragmentManager {
}
public void addFragment(Fragment fragment, boolean moveToStateNow) {
- if (DEBUG) Log.v(TAG, "add: " + fragment);
if (mAdded == null) {
mAdded = new ArrayList<Fragment>();
}
mAdded.add(fragment);
makeActive(fragment);
+ if (DEBUG) Log.v(TAG, "add: " + fragment);
fragment.mAdded = true;
if (fragment.mHasMenu) {
mNeedMenuInvalidate = true;
@@ -401,18 +401,18 @@ public class FragmentManager {
}
public void removeFragment(Fragment fragment, int transition, int transitionStyle) {
- if (DEBUG) Log.v(TAG, "remove: " + fragment);
+ if (DEBUG) Log.v(TAG, "remove: " + fragment + " nesting=" + fragment.mBackStackNesting);
mAdded.remove(fragment);
final boolean inactive = fragment.mBackStackNesting <= 0;
- if (inactive) {
- makeInactive(fragment);
- }
if (fragment.mHasMenu) {
mNeedMenuInvalidate = true;
}
fragment.mAdded = false;
moveToState(fragment, inactive ? Fragment.INITIALIZING : Fragment.CREATED,
transition, transitionStyle);
+ if (inactive) {
+ makeInactive(fragment);
+ }
}
public void hideFragment(Fragment fragment, int transition, int transitionStyle) {
diff --git a/core/java/android/app/LoaderManager.java b/core/java/android/app/LoaderManager.java
index 7fd5dde..e7bdd8b 100644
--- a/core/java/android/app/LoaderManager.java
+++ b/core/java/android/app/LoaderManager.java
@@ -18,6 +18,7 @@ package android.app;
import android.content.Loader;
import android.os.Bundle;
+import android.util.Log;
import android.util.SparseArray;
/**
@@ -87,8 +88,20 @@ public interface LoaderManager {
}
class LoaderManagerImpl implements LoaderManager {
+ static final String TAG = "LoaderManagerImpl";
+ static final boolean DEBUG = true;
+
+ // These are the currently active loaders. A loader is here
+ // from the time its load is started until it has been explicitly
+ // stopped or restarted by the application.
final SparseArray<LoaderInfo> mLoaders = new SparseArray<LoaderInfo>();
+
+ // These are previously run loaders. This list is maintained internally
+ // to avoid destroying a loader while an application is still using it.
+ // It allows an application to restart a loader, but continue using its
+ // previously run loader until the new loader's data is available.
final SparseArray<LoaderInfo> mInactiveLoaders = new SparseArray<LoaderInfo>();
+
boolean mStarted;
boolean mRetaining;
boolean mRetainingStarted;
@@ -125,6 +138,7 @@ class LoaderManagerImpl implements LoaderManager {
return;
}
+ if (DEBUG) Log.v(TAG, " Starting: " + this);
if (mLoader == null && mCallbacks != null) {
mLoader = mCallbacks.onCreateLoader(mId, mArgs);
}
@@ -139,6 +153,7 @@ class LoaderManagerImpl implements LoaderManager {
}
void retain() {
+ if (DEBUG) Log.v(TAG, " Retaining: " + this);
mRetaining = true;
mRetainingStarted = mStarted;
mStarted = false;
@@ -147,6 +162,7 @@ class LoaderManagerImpl implements LoaderManager {
void finishRetain() {
if (mRetaining) {
+ if (DEBUG) Log.v(TAG, " Finished Retaining: " + this);
mRetaining = false;
if (mStarted != mRetainingStarted) {
if (!mStarted) {
@@ -167,6 +183,7 @@ class LoaderManagerImpl implements LoaderManager {
}
void stop() {
+ if (DEBUG) Log.v(TAG, " Stopping: " + this);
mStarted = false;
if (mLoader != null && mListenerRegistered) {
// Let the loader know we're done with it
@@ -177,6 +194,7 @@ class LoaderManagerImpl implements LoaderManager {
}
void destroy() {
+ if (DEBUG) Log.v(TAG, " Destroying: " + this);
mDestroyed = true;
mCallbacks = null;
if (mLoader != null) {
@@ -189,6 +207,8 @@ class LoaderManagerImpl implements LoaderManager {
}
@Override public void onLoadComplete(Loader<Object> loader, Object data) {
+ if (DEBUG) Log.v(TAG, "onLoadComplete: " + this + " mDestroyed=" + mDestroyed);
+
if (mDestroyed) {
return;
}
@@ -200,19 +220,33 @@ class LoaderManagerImpl implements LoaderManager {
mCallbacks.onLoadFinished(loader, data);
}
- // Look for an inactive loader and destroy it if found
+ if (DEBUG) Log.v(TAG, "onLoadFinished returned: " + this);
+
+ // We have now given the application the new loader with its
+ // loaded data, so it should have stopped using the previous
+ // loader. If there is a previous loader on the inactive list,
+ // clean it up.
LoaderInfo info = mInactiveLoaders.get(mId);
- if (info != null) {
- Loader<Object> oldLoader = info.mLoader;
- if (oldLoader != null) {
- if (info.mListenerRegistered) {
- oldLoader.unregisterListener(info);
- }
- oldLoader.destroy();
- }
+ if (info != null && info != this) {
+ info.destroy();
mInactiveLoaders.remove(mId);
}
}
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder(64);
+ sb.append("LoaderInfo{");
+ sb.append(Integer.toHexString(System.identityHashCode(this)));
+ sb.append(" #");
+ sb.append(mId);
+ if (mArgs != null) {
+ sb.append(" ");
+ sb.append(mArgs.toString());
+ }
+ sb.append("}");
+ return sb.toString();
+ }
}
LoaderManagerImpl(boolean started) {
@@ -238,6 +272,8 @@ class LoaderManagerImpl implements LoaderManager {
public <D> Loader<D> initLoader(int id, Bundle args, LoaderManager.LoaderCallbacks<D> callback) {
LoaderInfo info = mLoaders.get(id);
+ if (DEBUG) Log.v(TAG, "initLoader in " + this + ": cur=" + info);
+
if (info == null) {
// Loader doesn't already exist; create.
info = createLoader(id, args, (LoaderManager.LoaderCallbacks<Object>)callback);
@@ -256,16 +292,30 @@ class LoaderManagerImpl implements LoaderManager {
@SuppressWarnings("unchecked")
public <D> Loader<D> restartLoader(int id, Bundle args, LoaderManager.LoaderCallbacks<D> callback) {
LoaderInfo info = mLoaders.get(id);
+ if (DEBUG) Log.v(TAG, "restartLoader in " + this + ": cur=" + info);
if (info != null) {
- if (mInactiveLoaders.get(id) != null) {
- // We already have an inactive loader for this ID that we are
- // waiting for! Now we have three active loaders... let's just
- // drop the one in the middle, since we are still waiting for
- // its result but that result is already out of date.
- info.destroy();
+ LoaderInfo inactive = mInactiveLoaders.get(id);
+ if (inactive != null) {
+ if (info.mData != null) {
+ // This loader now has data... we are probably being
+ // called from within onLoadComplete, where we haven't
+ // yet destroyed the last inactive loader. So just do
+ // that now.
+ if (DEBUG) Log.v(TAG, " Removing last inactive loader in " + this);
+ inactive.destroy();
+ mInactiveLoaders.put(id, info);
+ } else {
+ // We already have an inactive loader for this ID that we are
+ // waiting for! Now we have three active loaders... let's just
+ // drop the one in the middle, since we are still waiting for
+ // its result but that result is already out of date.
+ if (DEBUG) Log.v(TAG, " Removing intermediate loader in " + this);
+ info.destroy();
+ }
} else {
// Keep track of the previous instance of this loader so we can destroy
// it when the new one completes.
+ if (DEBUG) Log.v(TAG, " Making inactive: " + info);
mInactiveLoaders.put(id, info);
}
}
@@ -275,6 +325,7 @@ class LoaderManagerImpl implements LoaderManager {
}
public void stopLoader(int id) {
+ if (DEBUG) Log.v(TAG, "stopLoader in " + this + " of " + id);
int idx = mLoaders.indexOfKey(id);
if (idx >= 0) {
LoaderInfo info = mLoaders.valueAt(idx);
@@ -293,6 +344,8 @@ class LoaderManagerImpl implements LoaderManager {
}
void doStart() {
+ if (DEBUG) Log.v(TAG, "Starting: " + this);
+
// Call out to sub classes so they can start their loaders
// Let the existing loaders know that we want to be notified when a load is complete
for (int i = mLoaders.size()-1; i >= 0; i--) {
@@ -302,6 +355,8 @@ class LoaderManagerImpl implements LoaderManager {
}
void doStop() {
+ if (DEBUG) Log.v(TAG, "Stopping: " + this);
+
for (int i = mLoaders.size()-1; i >= 0; i--) {
mLoaders.valueAt(i).stop();
}
@@ -309,6 +364,8 @@ class LoaderManagerImpl implements LoaderManager {
}
void doRetain() {
+ if (DEBUG) Log.v(TAG, "Retaining: " + this);
+
mRetaining = true;
mStarted = false;
for (int i = mLoaders.size()-1; i >= 0; i--) {
@@ -317,6 +374,8 @@ class LoaderManagerImpl implements LoaderManager {
}
void finishRetain() {
+ if (DEBUG) Log.v(TAG, "Finished Retaining: " + this);
+
mRetaining = false;
for (int i = mLoaders.size()-1; i >= 0; i--) {
mLoaders.valueAt(i).finishRetain();
@@ -325,11 +384,13 @@ class LoaderManagerImpl implements LoaderManager {
void doDestroy() {
if (!mRetaining) {
+ if (DEBUG) Log.v(TAG, "Destroying Active: " + this);
for (int i = mLoaders.size()-1; i >= 0; i--) {
mLoaders.valueAt(i).destroy();
}
}
+ if (DEBUG) Log.v(TAG, "Destroying Inactive: " + this);
for (int i = mInactiveLoaders.size()-1; i >= 0; i--) {
mInactiveLoaders.valueAt(i).destroy();
}