diff options
-rw-r--r-- | api/current.xml | 160 | ||||
-rw-r--r-- | core/java/android/app/Fragment.java | 13 | ||||
-rw-r--r-- | core/java/android/app/FragmentManager.java | 23 | ||||
-rw-r--r-- | core/java/android/app/LoaderManager.java | 104 | ||||
-rw-r--r-- | core/java/android/content/AsyncTaskLoader.java | 6 | ||||
-rw-r--r-- | core/java/android/content/CursorLoader.java | 44 | ||||
-rw-r--r-- | core/java/android/content/Loader.java | 138 | ||||
-rw-r--r-- | core/java/android/os/AsyncTask.java | 2 | ||||
-rw-r--r-- | core/java/android/os/ParcelFileDescriptor.java | 2 | ||||
-rw-r--r-- | core/java/android/util/DebugUtils.java | 19 |
10 files changed, 386 insertions, 125 deletions
diff --git a/api/current.xml b/api/current.xml index 9ab1dd0..0bbdc88 100644 --- a/api/current.xml +++ b/api/current.xml @@ -30028,6 +30028,19 @@ <parameter name="args" type="java.lang.String[]"> </parameter> </method> +<method name="enableDebugLogging" + return="void" + abstract="false" + native="false" + synchronized="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="enabled" type="boolean"> +</parameter> +</method> <method name="executePendingTransactions" return="boolean" abstract="true" @@ -32314,6 +32327,19 @@ <parameter name="args" type="java.lang.String[]"> </parameter> </method> +<method name="enableDebugLogging" + return="void" + abstract="false" + native="false" + synchronized="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="enabled" type="boolean"> +</parameter> +</method> <method name="getLoader" return="android.content.Loader<D>" abstract="true" @@ -42885,17 +42911,6 @@ visibility="public" > </method> -<method name="forceLoad" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> <method name="loadInBackground" return="D" abstract="true" @@ -49578,28 +49593,6 @@ <parameter name="uri" type="android.net.Uri"> </parameter> </method> -<method name="startLoading" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="stopLoading" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> </class> <interface name="DialogInterface" abstract="true" @@ -54694,7 +54687,7 @@ </class> <class name="Loader" extends="java.lang.Object" - abstract="true" + abstract="false" static="false" final="false" deprecated="not deprecated" @@ -54710,6 +54703,19 @@ <parameter name="context" type="android.content.Context"> </parameter> </constructor> +<method name="dataToString" + return="java.lang.String" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="data" type="D"> +</parameter> +</method> <method name="deliverResult" return="void" abstract="false" @@ -54723,20 +54729,28 @@ <parameter name="data" type="D"> </parameter> </method> -<method name="destroy" +<method name="dump" return="void" abstract="false" native="false" synchronized="false" static="false" final="false" - deprecated="deprecated" + deprecated="not deprecated" visibility="public" > +<parameter name="prefix" type="java.lang.String"> +</parameter> +<parameter name="fd" type="java.io.FileDescriptor"> +</parameter> +<parameter name="writer" type="java.io.PrintWriter"> +</parameter> +<parameter name="args" type="java.lang.String[]"> +</parameter> </method> <method name="forceLoad" return="void" - abstract="true" + abstract="false" native="false" synchronized="false" static="false" @@ -54767,6 +54781,28 @@ visibility="public" > </method> +<method name="isReset" + return="boolean" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="isStarted" + return="boolean" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="onContentChanged" return="void" abstract="false" @@ -54778,6 +54814,50 @@ visibility="public" > </method> +<method name="onForceLoad" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="protected" +> +</method> +<method name="onReset" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="protected" +> +</method> +<method name="onStartLoading" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="protected" +> +</method> +<method name="onStopLoading" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="protected" +> +</method> <method name="registerListener" return="void" abstract="false" @@ -54806,7 +54886,7 @@ </method> <method name="startLoading" return="void" - abstract="true" + abstract="false" native="false" synchronized="false" static="false" @@ -54817,7 +54897,7 @@ </method> <method name="stopLoading" return="void" - abstract="true" + abstract="false" native="false" synchronized="false" static="false" @@ -143200,7 +143280,7 @@ synchronized="false" static="true" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <parameter name="data" type="byte[]"> diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java index 348149e..f06f2cf 100644 --- a/core/java/android/app/Fragment.java +++ b/core/java/android/app/Fragment.java @@ -27,6 +27,7 @@ import android.os.Parcel; import android.os.Parcelable; import android.util.AndroidRuntimeException; import android.util.AttributeSet; +import android.util.DebugUtils; import android.util.SparseArray; import android.view.ContextMenu; import android.view.LayoutInflater; @@ -526,17 +527,7 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener @Override public String toString() { StringBuilder sb = new StringBuilder(128); - String simpleName = getClass().getSimpleName(); - if (simpleName == null || simpleName.isEmpty()) { - simpleName = getClass().getName(); - int end = simpleName.lastIndexOf('.'); - if (end > 0) { - simpleName = simpleName.substring(end+1); - } - } - sb.append(simpleName); - sb.append("{"); - sb.append(Integer.toHexString(System.identityHashCode(this))); + DebugUtils.buildShortClassTag(this, sb); if (mIndex >= 0) { sb.append(" #"); sb.append(mIndex); diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java index 488b673..fe2ebed 100644 --- a/core/java/android/app/FragmentManager.java +++ b/core/java/android/app/FragmentManager.java @@ -26,6 +26,7 @@ import android.os.Handler; import android.os.Looper; import android.os.Parcel; import android.os.Parcelable; +import android.util.DebugUtils; import android.util.Log; import android.util.SparseArray; import android.view.Menu; @@ -251,6 +252,15 @@ public abstract class FragmentManager { * @param args Additional arguments to the dump request. */ public abstract void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args); + + /** + * Control whether the framework's internal fragment manager debugging + * logs are turned on. If enabled, you will see output in logcat as + * the framework performs fragment operations. + */ + public static void enableDebugLogging(boolean enabled) { + FragmentManagerImpl.DEBUG = enabled; + } } final class FragmentManagerState implements Parcelable { @@ -293,7 +303,7 @@ final class FragmentManagerState implements Parcelable { * Container for fragments associated with an activity. */ final class FragmentManagerImpl extends FragmentManager { - static final boolean DEBUG = false; + static boolean DEBUG = true; static final String TAG = "FragmentManager"; static final String TARGET_REQUEST_CODE_STATE_TAG = "android:target_req_state"; @@ -451,6 +461,17 @@ final class FragmentManagerImpl extends FragmentManager { } @Override + public String toString() { + StringBuilder sb = new StringBuilder(128); + sb.append("FragmentManager{"); + sb.append(Integer.toHexString(System.identityHashCode(this))); + sb.append(" in "); + DebugUtils.buildShortClassTag(mActivity, sb); + sb.append("}}"); + return sb.toString(); + } + + @Override public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { if (mActive == null || mActive.size() <= 0) { return; diff --git a/core/java/android/app/LoaderManager.java b/core/java/android/app/LoaderManager.java index 7125054..0e97abb 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.DebugUtils; import android.util.Log; import android.util.SparseArray; @@ -122,6 +123,8 @@ public abstract class LoaderManager { * @param id A unique identifier for this loader. Can be whatever you want. * Identifiers are scoped to a particular LoaderManager instance. * @param args Optional arguments to supply to the loader at construction. + * If a loader already exists (a new one does not need to be created), this + * parameter will be ignored and the last arguments continue to be used. * @param callback Interface the LoaderManager will call to report about * changes in the state of the loader. Required. */ @@ -177,11 +180,20 @@ public abstract class LoaderManager { * @param args Additional arguments to the dump request. */ public abstract void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args); + + /** + * Control whether the framework's internal loader manager debugging + * logs are turned on. If enabled, you will see output in logcat as + * the framework performs loader operations. + */ + public static void enableDebugLogging(boolean enabled) { + LoaderManagerImpl.DEBUG = enabled; + } } class LoaderManagerImpl extends LoaderManager { - static final String TAG = "LoaderManagerImpl"; - static final boolean DEBUG = true; + static final String TAG = "LoaderManager"; + static 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 @@ -237,6 +249,11 @@ class LoaderManagerImpl extends LoaderManager { mLoader = mCallbacks.onCreateLoader(mId, mArgs); } if (mLoader != null) { + if (mLoader.getClass().isMemberClass()) { + throw new IllegalArgumentException( + "Object returned from onCreateLoader must not be a member class: " + + mLoader); + } if (!mListenerRegistered) { mLoader.registerListener(mId, this); mListenerRegistered = true; @@ -295,7 +312,10 @@ class LoaderManagerImpl extends LoaderManager { void destroy() { if (DEBUG) Log.v(TAG, " Destroying: " + this); mDestroyed = true; - if (mCallbacks != null && mLoader != null && mData != null && mNeedReset) { + boolean needReset = mNeedReset; + mNeedReset = false; + if (mCallbacks != null && mLoader != null && mData != null && needReset) { + if (DEBUG) Log.v(TAG, " Reseting: " + this); String lastBecause = null; if (mActivity != null) { lastBecause = mActivity.mFragments.mNoTransactionsBecause; @@ -309,7 +329,6 @@ class LoaderManagerImpl extends LoaderManager { } } } - mNeedReset = false; mCallbacks = null; mData = null; if (mLoader != null) { @@ -322,9 +341,10 @@ class LoaderManagerImpl extends LoaderManager { } @Override public void onLoadComplete(Loader<Object> loader, Object data) { - if (DEBUG) Log.v(TAG, "onLoadComplete: " + this + " mDestroyed=" + mDestroyed); + if (DEBUG) Log.v(TAG, "onLoadComplete: " + this); if (mDestroyed) { + if (DEBUG) Log.v(TAG, " Ignoring load complete -- destroyed"); return; } @@ -335,7 +355,7 @@ class LoaderManagerImpl extends LoaderManager { callOnLoadFinished(loader, data); } - if (DEBUG) Log.v(TAG, "onLoadFinished returned: " + this); + //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 @@ -357,6 +377,8 @@ class LoaderManagerImpl extends LoaderManager { mActivity.mFragments.mNoTransactionsBecause = "onLoadFinished"; } try { + if (DEBUG) Log.v(TAG, " onLoadFinished in " + loader + ": " + + loader.dataToString(data)); mCallbacks.onLoadFinished(loader, data); } finally { if (mActivity != null) { @@ -374,21 +396,9 @@ class LoaderManagerImpl extends LoaderManager { 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(); - } - - public String toBasicString() { - StringBuilder sb = new StringBuilder(64); - sb.append("LoaderInfo{"); - sb.append(Integer.toHexString(System.identityHashCode(this))); - sb.append(" #"); - sb.append(mId); - sb.append("}"); + sb.append(" : "); + DebugUtils.buildShortClassTag(mLoader, sb); + sb.append("}}"); return sb.toString(); } @@ -397,6 +407,9 @@ class LoaderManagerImpl extends LoaderManager { writer.print(" mArgs="); writer.println(mArgs); writer.print(prefix); writer.print("mCallbacks="); writer.println(mCallbacks); writer.print(prefix); writer.print("mLoader="); writer.println(mLoader); + if (mLoader != null) { + mLoader.dump(prefix + " ", fd, writer, args); + } writer.print(prefix); writer.print("mData="); writer.println(mData); writer.print(prefix); writer.print("mStarted="); writer.print(mStarted); writer.print(" mRetaining="); writer.print(mRetaining); @@ -434,12 +447,14 @@ class LoaderManagerImpl extends 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 (DEBUG) Log.v(TAG, "initLoader in " + this + ": args=" + args); if (info == null) { // Loader doesn't already exist; create. info = createLoader(id, args, (LoaderManager.LoaderCallbacks<Object>)callback); + if (DEBUG) Log.v(TAG, " Created new loader " + info); } else { + if (DEBUG) Log.v(TAG, " Re-using existing loader " + info); info.mCallbacks = (LoaderManager.LoaderCallbacks<Object>)callback; } @@ -454,7 +469,7 @@ class LoaderManagerImpl extends 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 (DEBUG) Log.v(TAG, "restartLoader in " + this + ": args=" + args); if (info != null) { LoaderInfo inactive = mInactiveLoaders.get(id); if (inactive != null) { @@ -463,7 +478,7 @@ class LoaderManagerImpl extends LoaderManager { // 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); + if (DEBUG) Log.v(TAG, " Removing last inactive loader: " + info); inactive.mNeedReset = false; inactive.destroy(); mInactiveLoaders.put(id, info); @@ -472,13 +487,13 @@ class LoaderManagerImpl extends LoaderManager { // 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); + if (DEBUG) Log.v(TAG, " Removing intermediate loader: " + info); 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); + if (DEBUG) Log.v(TAG, " Making last loader inactive: " + info); mInactiveLoaders.put(id, info); } } @@ -488,7 +503,7 @@ class LoaderManagerImpl extends LoaderManager { } public void destroyLoader(int id) { - if (DEBUG) Log.v(TAG, "stopLoader in " + this + " of " + id); + if (DEBUG) Log.v(TAG, "destroyLoader in " + this + " of " + id); int idx = mLoaders.indexOfKey(id); if (idx >= 0) { LoaderInfo info = mLoaders.valueAt(idx); @@ -513,7 +528,7 @@ class LoaderManagerImpl extends LoaderManager { } void doStart() { - if (DEBUG) Log.v(TAG, "Starting: " + this); + if (DEBUG) Log.v(TAG, "Starting in " + this); if (mStarted) { RuntimeException e = new RuntimeException("here"); e.fillInStackTrace(); @@ -531,7 +546,7 @@ class LoaderManagerImpl extends LoaderManager { } void doStop() { - if (DEBUG) Log.v(TAG, "Stopping: " + this); + if (DEBUG) Log.v(TAG, "Stopping in " + this); if (!mStarted) { RuntimeException e = new RuntimeException("here"); e.fillInStackTrace(); @@ -546,7 +561,7 @@ class LoaderManagerImpl extends LoaderManager { } void doRetain() { - if (DEBUG) Log.v(TAG, "Retaining: " + this); + if (DEBUG) Log.v(TAG, "Retaining in " + this); if (!mStarted) { RuntimeException e = new RuntimeException("here"); e.fillInStackTrace(); @@ -562,23 +577,25 @@ class LoaderManagerImpl extends LoaderManager { } void finishRetain() { - if (DEBUG) Log.v(TAG, "Finished Retaining: " + this); + if (mRetaining) { + if (DEBUG) Log.v(TAG, "Finished Retaining in " + this); - mRetaining = false; - for (int i = mLoaders.size()-1; i >= 0; i--) { - mLoaders.valueAt(i).finishRetain(); + mRetaining = false; + for (int i = mLoaders.size()-1; i >= 0; i--) { + mLoaders.valueAt(i).finishRetain(); + } } } void doDestroy() { if (!mRetaining) { - if (DEBUG) Log.v(TAG, "Destroying Active: " + this); + if (DEBUG) Log.v(TAG, "Destroying Active in " + this); for (int i = mLoaders.size()-1; i >= 0; i--) { mLoaders.valueAt(i).destroy(); } } - if (DEBUG) Log.v(TAG, "Destroying Inactive: " + this); + if (DEBUG) Log.v(TAG, "Destroying Inactive in " + this); for (int i = mInactiveLoaders.size()-1; i >= 0; i--) { mInactiveLoaders.valueAt(i).destroy(); } @@ -586,6 +603,17 @@ class LoaderManagerImpl extends LoaderManager { } @Override + public String toString() { + StringBuilder sb = new StringBuilder(128); + sb.append("LoaderManager{"); + sb.append(Integer.toHexString(System.identityHashCode(this))); + sb.append(" in "); + DebugUtils.buildShortClassTag(mActivity, sb); + sb.append("}}"); + return sb.toString(); + } + + @Override public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { if (mLoaders.size() > 0) { writer.print(prefix); writer.println("Active Loaders:"); @@ -593,7 +621,7 @@ class LoaderManagerImpl extends LoaderManager { for (int i=0; i < mLoaders.size(); i++) { LoaderInfo li = mLoaders.valueAt(i); writer.print(prefix); writer.print(" #"); writer.print(mLoaders.keyAt(i)); - writer.print(": "); writer.println(li.toBasicString()); + writer.print(": "); writer.println(li.toString()); li.dump(innerPrefix, fd, writer, args); } } @@ -603,7 +631,7 @@ class LoaderManagerImpl extends LoaderManager { for (int i=0; i < mInactiveLoaders.size(); i++) { LoaderInfo li = mInactiveLoaders.valueAt(i); writer.print(prefix); writer.print(" #"); writer.print(mInactiveLoaders.keyAt(i)); - writer.print(": "); writer.println(li.toBasicString()); + writer.print(": "); writer.println(li.toString()); li.dump(innerPrefix, fd, writer, args); } } diff --git a/core/java/android/content/AsyncTaskLoader.java b/core/java/android/content/AsyncTaskLoader.java index b19c072..30f8ffc 100644 --- a/core/java/android/content/AsyncTaskLoader.java +++ b/core/java/android/content/AsyncTaskLoader.java @@ -53,12 +53,8 @@ public abstract class AsyncTaskLoader<D> extends Loader<D> { super(context); } - /** - * Force an asynchronous load. Unlike {@link #startLoading()} this will ignore a previously - * loaded data set and load a new one. - */ @Override - public void forceLoad() { + protected void onForceLoad() { cancelLoad(); mTask = new LoadTask(); mTask.execute((Void[]) null); diff --git a/core/java/android/content/CursorLoader.java b/core/java/android/content/CursorLoader.java index 9e03c25..91dd23b 100644 --- a/core/java/android/content/CursorLoader.java +++ b/core/java/android/content/CursorLoader.java @@ -20,21 +20,25 @@ import android.database.ContentObserver; import android.database.Cursor; import android.net.Uri; +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.Arrays; + /** * A loader that queries the {@link ContentResolver} and returns a {@link Cursor}. */ public class CursorLoader extends AsyncTaskLoader<Cursor> { - Cursor mCursor; - ForceLoadContentObserver mObserver; - boolean mStopped; - boolean mContentChanged; - boolean mReset; + final ForceLoadContentObserver mObserver; + Uri mUri; String[] mProjection; String mSelection; String[] mSelectionArgs; String mSortOrder; + Cursor mCursor; + boolean mContentChanged; + /* Runs on a worker thread */ @Override public Cursor loadInBackground() { @@ -69,7 +73,7 @@ public class CursorLoader extends AsyncTaskLoader<Cursor> { Cursor oldCursor = mCursor; mCursor = cursor; - if (!mStopped) { + if (isStarted()) { super.deliverResult(cursor); } @@ -97,10 +101,7 @@ public class CursorLoader extends AsyncTaskLoader<Cursor> { * Must be called from the UI thread */ @Override - public void startLoading() { - mStopped = false; - mReset = false; - + protected void onStartLoading() { if (mCursor != null) { deliverResult(mCursor); } @@ -114,17 +115,14 @@ public class CursorLoader extends AsyncTaskLoader<Cursor> { * Must be called from the UI thread */ @Override - public void stopLoading() { + protected void onStopLoading() { // Attempt to cancel the current load task if possible. cancelLoad(); - - // Make sure that any outstanding loads clean themselves up properly - mStopped = true; } @Override public void onContentChanged() { - if (mStopped) { + if (!isStarted()) { // This loader has been stopped, so we don't want to load // new data right now... but keep track of it changing to // refresh later if we start again. @@ -142,7 +140,7 @@ public class CursorLoader extends AsyncTaskLoader<Cursor> { } @Override - public void reset() { + protected void onReset() { mReset = true; // Ensure the loader is stopped @@ -193,4 +191,18 @@ public class CursorLoader extends AsyncTaskLoader<Cursor> { public void setSortOrder(String sortOrder) { mSortOrder = sortOrder; } + + @Override + public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { + super.dump(prefix, fd, writer, args); + writer.print(prefix); writer.print("mUri="); writer.println(mUri); + writer.print(prefix); writer.print("mProjection="); + writer.println(Arrays.toString(mProjection)); + writer.print(prefix); writer.print("mSelection="); writer.println(mSelection); + writer.print(prefix); writer.print("mSelectionArgs="); + writer.println(Arrays.toString(mSelectionArgs)); + writer.print(prefix); writer.print("mSortOrder="); writer.println(mSortOrder); + writer.print(prefix); writer.print("mCursor="); writer.println(mCursor); + writer.print(prefix); writer.print("mContentChanged="); writer.println(mContentChanged); + } } diff --git a/core/java/android/content/Loader.java b/core/java/android/content/Loader.java index 73d7103..f425b29 100644 --- a/core/java/android/content/Loader.java +++ b/core/java/android/content/Loader.java @@ -18,18 +18,27 @@ package android.content; import android.database.ContentObserver; import android.os.Handler; +import android.util.DebugUtils; + +import java.io.FileDescriptor; +import java.io.PrintWriter; /** * An abstract class that performs asynchronous loading of data. While Loaders are active * they should monitor the source of their data and deliver new results when the contents * change. * + * <p>Subclasses generally must implement at least {@link #onStartLoading()}, + * {@link #onStopLoading()}, {@link #onForceLoad()}, and {@link #onReset()}. + * * @param <D> The result returned when the load is complete */ -public abstract class Loader<D> { +public class Loader<D> { int mId; OnLoadCompleteListener<D> mListener; Context mContext; + boolean mStarted = false; + boolean mReset = true; public final class ForceLoadContentObserver extends ContentObserver { public ForceLoadContentObserver() { @@ -122,28 +131,88 @@ public abstract class Loader<D> { } /** + * Return whether this load has been started. That is, its {@link #startLoading()} + * has been called and no calls to {@link #stopLoading()} or + * {@link #reset()} have yet been made. + */ + public boolean isStarted() { + return mStarted; + } + + /** + * Return whether this load has been reset. That is, either the loader + * has not yet been started for the first time, or its {@link #reset()} + * has been called. + */ + public boolean isReset() { + return mReset; + } + + /** * Starts an asynchronous load of the contacts list data. When the result is ready the callbacks * will be called on the UI thread. If a previous load has been completed and is still valid * the result may be passed to the callbacks immediately. The loader will monitor the source of * the data set and may deliver future callbacks if the source changes. Calling * {@link #stopLoading} will stop the delivery of callbacks. * - * <p>Must be called from the UI thread + * <p>This updates the Loader's internal state so that + * {@link #isStarted()} and {@link #isReset()} will return the correct + * values, and then calls the implementation's {@link #onStartLoading()}. + * + * <p>Must be called from the UI thread. + */ + public void startLoading() { + mStarted = true; + mReset = false; + onStartLoading(); + } + + /** + * Subclasses must implement this to take care of loading their data, + * as per {@link #startLoading()}. This is not called by clients directly, + * but as a result of a call to {@link #startLoading()}. */ - public abstract void startLoading(); + protected void onStartLoading() { + } /** * Force an asynchronous load. Unlike {@link #startLoading()} this will ignore a previously - * loaded data set and load a new one. + * loaded data set and load a new one. This simply calls through to the + * implementation's {@link #onForceLoad()}. + * + * <p>Must be called from the UI thread. */ - public abstract void forceLoad(); + public void forceLoad() { + onForceLoad(); + } /** - * Stops delivery of updates until the next time {@link #startLoading()} is called + * Subclasses must implement this to take care of requests to {@link #forceLoad()}. + */ + protected void onForceLoad() { + } + + /** + * Stops delivery of updates until the next time {@link #startLoading()} is called. * - * <p>Must be called from the UI thread + * <p>This updates the Loader's internal state so that + * {@link #isStarted()} will return the correct + * value, and then calls the implementation's {@link #onStopLoading()}. + * + * <p>Must be called from the UI thread. */ - public abstract void stopLoading(); + public void stopLoading() { + mStarted = false; + onStopLoading(); + } + + /** + * Subclasses must implement this to take care of stopping their loader, + * as per {@link #stopLoading()}. This is not called by clients directly, + * but as a result of a call to {@link #stopLoading()}. + */ + protected void onStopLoading() { + } /** * Resets the state of the Loader. The Loader should at this point free @@ -151,17 +220,24 @@ public abstract class Loader<D> { * {@link #startLoading()} may later be called at which point it must be * able to start running again. * - * <p>Must be called from the UI thread + * <p>This updates the Loader's internal state so that + * {@link #isStarted()} and {@link #isReset()} will return the correct + * values, and then calls the implementation's {@link #onReset()}. + * + * <p>Must be called from the UI thread. */ public void reset() { - destroy(); + onReset(); + mReset = true; + mStarted = false; } /** - * @deprecated Old API, implement reset() now. + * Subclasses must implement this to take care of resetting their loader, + * as per {@link #reset()}. This is not called by clients directly, + * but as a result of a call to {@link #reset()}. */ - @Deprecated - public void destroy() { + protected void onReset() { } /** @@ -173,4 +249,40 @@ public abstract class Loader<D> { public void onContentChanged() { forceLoad(); } + + /** + * For debugging, converts an instance of the Loader's data class to + * a string that can be printed. Must handle a null data. + */ + public String dataToString(D data) { + StringBuilder sb = new StringBuilder(64); + DebugUtils.buildShortClassTag(data, sb); + sb.append("}"); + return sb.toString(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(64); + DebugUtils.buildShortClassTag(this, sb); + sb.append(" id="); + sb.append(mId); + sb.append("}"); + return sb.toString(); + } + + /** + * Print the Loader's state into the given stream. + * + * @param prefix Text to print at the front of each line. + * @param fd The raw file descriptor that the dump is being sent to. + * @param writer A PrintWriter to which the dump is to be set. + * @param args Additional arguments to the dump request. + */ + public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { + writer.print(prefix); writer.print("mId="); writer.print(mId); + writer.print(" mListener="); writer.println(mListener); + writer.print(prefix); writer.print("mStarted="); writer.print(mStarted); + writer.print(" mReset="); writer.println(mReset); + } }
\ No newline at end of file diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java index f0309d6..9d5d742 100644 --- a/core/java/android/os/AsyncTask.java +++ b/core/java/android/os/AsyncTask.java @@ -281,7 +281,7 @@ public abstract class AsyncTask<Params, Progress, Result> { /** * Runs on the UI thread after {@link #doInBackground}. The * specified result is the value returned by {@link #doInBackground} - * or null if the task was cancelled or an exception occured. + * or null if the task was cancelled or an exception occurred. * * @param result The result of the operation computed by {@link #doInBackground}. * diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java index 5f6c4f0..b6c2ed6 100644 --- a/core/java/android/os/ParcelFileDescriptor.java +++ b/core/java/android/os/ParcelFileDescriptor.java @@ -153,6 +153,7 @@ public class ParcelFileDescriptor implements Parcelable { private static native int createPipeNative(FileDescriptor[] outFds); /** + * @deprecated Please use createPipe() or ContentProvider.openPipeHelper(). * Gets a file descriptor for a read-only copy of the given data. * * @param data Data to copy. @@ -161,6 +162,7 @@ public class ParcelFileDescriptor implements Parcelable { * @return A ParcelFileDescriptor. * @throws IOException if there is an error while creating the shared memory area. */ + @Deprecated public static ParcelFileDescriptor fromData(byte[] data, String name) throws IOException { if (data == null) return null; MemoryFile file = new MemoryFile(name, data.length); diff --git a/core/java/android/util/DebugUtils.java b/core/java/android/util/DebugUtils.java index 56f389c..65fc35c 100644 --- a/core/java/android/util/DebugUtils.java +++ b/core/java/android/util/DebugUtils.java @@ -101,4 +101,23 @@ public class DebugUtils { return match; } + /** @hide */ + public static void buildShortClassTag(Object cls, StringBuilder out) { + if (cls == null) { + out.append("null"); + } else { + String simpleName = cls.getClass().getSimpleName(); + if (simpleName == null || simpleName.isEmpty()) { + simpleName = cls.getClass().getName(); + int end = simpleName.lastIndexOf('.'); + if (end > 0) { + simpleName = simpleName.substring(end+1); + } + } + out.append(simpleName); + out.append('{'); + out.append(Integer.toHexString(System.identityHashCode(cls))); + } + } + } |