More cleanup of Loader APIs.
- Remove old method names.
- Introduce onXxx() hooks to Loader.
- Improve debugging.
Change-Id: I3fba072a05c7023aa7d2c3eb4e126feb514ab6d8
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 @@
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 @@
}
/**
+ * 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 abstract void startLoading();
+ 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()}.
+ */
+ 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
- *
- * <p>Must be called from the UI thread
+ * Subclasses must implement this to take care of requests to {@link #forceLoad()}.
*/
- public abstract void stopLoading();
+ protected void onForceLoad() {
+ }
+
+ /**
+ * Stops delivery of updates until the next time {@link #startLoading()} is called.
+ *
+ * <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 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 @@
* {@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 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