From 50c2275cff28c4a216f6924584e43cd64b90a3bf Mon Sep 17 00:00:00 2001 From: Joe Malin Date: Sat, 20 Oct 2012 12:41:40 -0700 Subject: Android Training: CursorLoader Change-Id: Ia8d723b5ce32002597b9444b8c7eff07b1ab29c8 --- .../load-data-background/define-launch-query.jd | 83 +++++++++++++++ .../load-data-background/handle-results.jd | 104 ++++++++++++++++++ docs/html/training/load-data-background/index.jd | 117 +++++++++++++++++++++ .../training/load-data-background/setup-loader.jd | 90 ++++++++++++++++ docs/html/training/training_toc.cs | 63 +++++++---- 5 files changed, 435 insertions(+), 22 deletions(-) create mode 100644 docs/html/training/load-data-background/define-launch-query.jd create mode 100644 docs/html/training/load-data-background/handle-results.jd create mode 100644 docs/html/training/load-data-background/index.jd create mode 100644 docs/html/training/load-data-background/setup-loader.jd diff --git a/docs/html/training/load-data-background/define-launch-query.jd b/docs/html/training/load-data-background/define-launch-query.jd new file mode 100644 index 000000000000..f7978f4a8984 --- /dev/null +++ b/docs/html/training/load-data-background/define-launch-query.jd @@ -0,0 +1,83 @@ +page.title=Defining and Launching the Query +trainingnavtop=true +startpage=true + +@jd:body + + +
+
+

This lesson teaches you to

+
    +
  1. + Define and Launch the Query +
  2. +
+
+
+ +

+ To perform a query, create the {@link android.support.v4.content.CursorLoader}, set up its + query, and pass it to the loader framework. From then on, the framework manages everything. + It runs the query on a background thread, returns the results to the foreground, and + watches for changes to the data associated with the query. +

+

+ Pass a {@link android.support.v4.content.CursorLoader} to the loader framework in + your implementation of + {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()}. + The loader framework calls this method when you create a loader by calling + {@link android.support.v4.app.LoaderManager#initLoader initLoader()}. You can create + a {@link android.support.v4.content.CursorLoader} anywhere, + but the preferred way is to create it in + {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()}, + because this defers creation until the object is actually needed. +

+

+ Notice that {@link android.support.v4.app.LoaderManager#initLoader initLoader()} will only + {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()} + if the {@link android.support.v4.content.CursorLoader} doesn't already exist; otherwise, it + re-uses the existing {@link android.support.v4.content.CursorLoader}. The loader framework + tracks {@link android.support.v4.content.CursorLoader} instance using the id + value passed to {@link android.support.v4.app.LoaderManager#initLoader initLoader()}. +

+

Define and Launch the Query

+

+ To create a {@link android.support.v4.content.CursorLoader} and define its + query at the same time, call the constructor +{@link android.support.v4.content.CursorLoader#CursorLoader(Context, Uri, String[], String, String[], String) + CursorLoader(context, uri, projection, selection, selectionArgs, sortOrder)}. The + context and uri arguments are required, but the others are optional. + To use the default value for an optional argument, pass in null. The + {@link android.support.v4.content.CursorLoader} runs the query against the + {@link android.content.ContentProvider} identified by uri, just as if you had + called {@link android.content.ContentResolver#query ContentResolver.query()} with the same + arguments. +

+

+ For example: +

+
+public Loader<Cursor> onCreateLoader(int loaderID, Bundle bundle)
+{
+    /*
+     * Takes action based on the ID of the Loader that's being created
+     */
+    switch (loaderID) {
+        case URL_LOADER:
+            /*
+             * Return a new CursorLoader
+             */
+            return new CursorLoader(
+                this,                           // Context
+                DataProviderContract.IMAGE_URI, // Provider's content URI
+                PROJECTION,                     // Columns to return
+                null,                           // Return all rows
+                null,                           // No search arguments
+                null);                          // Default search order
+        default:
+            // An invalid id was passed in
+            return null;
+    }
+}
+
diff --git a/docs/html/training/load-data-background/handle-results.jd b/docs/html/training/load-data-background/handle-results.jd new file mode 100644 index 000000000000..f8e003a3401f --- /dev/null +++ b/docs/html/training/load-data-background/handle-results.jd @@ -0,0 +1,104 @@ +page.title=Handling the Results +trainingnavtop=true +startpage=true + +@jd:body + + +
+
+

This lesson teaches you to

+
    +
  1. + Handle Query Results +
  2. +
  3. + Clear Out Old Data
  4. +
+
+
+ +

+ {@link android.support.v4.content.CursorLoader} returns its query results to your + implementation of + {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoadFinished + LoaderCallbacks.onLoadFinished()}, in the form of a {@link android.database.Cursor}. In the + callback, you can update your data display, do further processing on the + {@link android.database.Cursor} data, and so forth. +

+

+ When the loader framework detects changes to data associated with the query, + it resets the {@link android.support.v4.content.CursorLoader}, closes the current + {@link android.database.Cursor}, and then invokes your implementation of + {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoaderReset onLoaderReset()}. + Use this callback to delete references to the current {@link android.database.Cursor}; when the + loader framework destroys the {@link android.database.Cursor}, you won't have outstanding + references that cause memory leaks. +

+

Handle Query Results

+

+ The following two snippets are an example of displaying the results of a query, using a + {@link android.widget.ListView} backed by a + {@link android.support.v4.widget.SimpleCursorAdapter}. +

+

+ The first snippet shows the {@link android.widget.ListView} and + {@link android.support.v4.widget.SimpleCursorAdapter}: +

+
+// Gets a handle to the Android built-in ListView widget
+mListView = ((ListView) findViewById(android.R.id.list));
+// Creates a CursorAdapter
+mAdapter =
+    new SimpleCursorAdapter(
+    this,                   // Current context
+    R.layout.logitem,       // View for each item in the list
+    null,                   // Don't provide the cursor yet
+    FROM_COLUMNS,           // List of cursor columns to display
+    TO_FIELDS,              // List of TextViews in each line
+    0                       // flags
+);
+// Links the adapter to the ListView
+mListView.setAdapter(mAdapter);
+
+

+ The next snippet shows an implementation of + {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()} + that moves the query results in the returned {@link android.database.Cursor} to the + {@link android.support.v4.widget.SimpleCursorAdapter}. Changing the + {@link android.database.Cursor} in the + {@link android.support.v4.widget.SimpleCursorAdapter} triggers a refresh of the + {@link android.widget.ListView} with the new data: +

+
+public void onLoadFinished(Loader<Cursor> loader, Cursor cursor)
+{
+    /*
+     * Move the results into the adapter. This
+     * triggers the ListView to re-display.
+     */
+    mAdapter.swapCursor(cursor);
+}
+
+

Handle a Loader Reset

+

+ The loader framework resets the {@link android.support.v4.content.CursorLoader} whenever the + {@link android.database.Cursor} becomes invalid. This usually occurs because the data associated + with the {@link android.database.Cursor} has changed. Before re-running the query, + the framework calls your implementation of + {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoaderReset onLoaderReset()}. In + this callback, make sure to prevent memory leaks by deleting all references to the current + {@link android.database.Cursor}. Once you return from + {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoaderReset onLoaderReset()}, + the loader framework re-runs the query. +

+

+ For example: +

+
+public void onLoaderReset(Loader<Cursor> loader)
+{
+    // Remove the reference to the current Cursor
+    mAdapter.swapCursor(null);
+}
+
diff --git a/docs/html/training/load-data-background/index.jd b/docs/html/training/load-data-background/index.jd new file mode 100644 index 000000000000..574a32cc0e40 --- /dev/null +++ b/docs/html/training/load-data-background/index.jd @@ -0,0 +1,117 @@ +page.title=Loading Data in the Background +trainingnavtop=true +startpage=true + +@jd:body +
+
+ + +

Dependencies and prerequisites

+

Dependencies

+
    +
  • + Android 1.6 or later +
  • +
+

Prerequisites

+ + + +

You should also read

+ +
+
+

+ A {@link android.support.v4.content.CursorLoader} runs a query against a + {@link android.content.ContentProvider} on a background thread and returns a + {@link android.database.Cursor} to the main thread. +

+

+ {@link android.support.v4.content.CursorLoader} has these advantages over alternate ways of + running a query: +

+
+
+ Query on a background thread +
+
+ A {@link android.support.v4.content.CursorLoader} query runs asynchronously on a + background thread, so it doesn't cause "Application Not Responding" (ANR) errors on the UI + thread. {@link android.support.v4.content.CursorLoader} creates and starts the + background thread; all you have to do is initialize the loader framework and handle the + results of the query. +
+
+ Automatic re-query +
+
+ A {@link android.support.v4.content.CursorLoader} automatically runs a new query when + the loader framework detects that the data underlying the {@link android.database.Cursor} + has changed. +
+
+ Simple API +
+
+ The {@link android.support.v4.content.CursorLoader} API provides the + query framework and cursor monitoring that you would have to define yourself if you used + {@link android.os.AsyncTask}. +
+
+

+ A {@link android.support.v4.content.CursorLoader} is limited in that the query must be + against a {@link android.net.Uri} and must return a {@link android.database.Cursor}. Because of + this, a {@link android.support.v4.content.CursorLoader} can only run a query against a + {@link android.content.ContentProvider}. +

+

+ This class describes how to define and use a {@link android.support.v4.content.CursorLoader}. + Examples in this class use the {@link android.support.v4 v4 support library} versions of + classes, which support platforms starting with Android 1.6. +

+

Lessons

+
+
+ Setting Up the Loader +
+
+ Learn how to set up an {@link android.app.Activity} that inherits the necessary classes + for running a {@link android.support.v4.content.CursorLoader} and returning results. +
+
+ Defining and Launching the Query +
+
+ Learn how to perform a query against a {@link android.content.ContentProvider} using + a {@link android.support.v4.content.CursorLoader}. +
+
+ + Handling the Results + +
+
+ Learn how to handle the {@link android.database.Cursor} returned from the query, and how + to remove references to the current {@link android.database.Cursor} when the loader + framework re-sets the {@link android.support.v4.content.CursorLoader}. +
+
diff --git a/docs/html/training/load-data-background/setup-loader.jd b/docs/html/training/load-data-background/setup-loader.jd new file mode 100644 index 000000000000..4b406116ff6c --- /dev/null +++ b/docs/html/training/load-data-background/setup-loader.jd @@ -0,0 +1,90 @@ +page.title=Setting Up the Loader +trainingnavtop=true +startpage=true + +@jd:body + + +
+
+

This lesson teaches you to

+
    +
  1. + Extend an Activity +
  2. +
  3. + Retrieve a LoaderManager +
  4. +
  5. + Initialize the Loader Framework +
  6. +
+
+
+

+ You create a {@link android.support.v4.content.CursorLoader} within a + loader framework. To set up the framework, you implement the + {@link android.support.v4.app.LoaderManager.LoaderCallbacks LoaderCallbacks<Cursor>} + as part of an {@link android.app.Activity}. In addition, to provide compatibility + compatible with platform versions starting with Android 1.6, you must extend the + {@link android.app.Activity} with the {@link android.support.v4.app.FragmentActivity} class. +

+

+ Note: A {@link android.support.v4.app.Fragment} is not a prerequisite for + {@link android.support.v4.content.CursorLoader}. As a convenience, the support library class + {@link android.support.v4.app.FragmentActivity} contains the fragment and the loader frameworks, + but they are completely independent of each other. +

+

+ Before you can use the loader framework, you need to initialize it. To do this, retrieve + a {@link android.support.v4.app.LoaderManager} object and call its + {@link android.support.v4.app.LoaderManager#initLoader initLoader()} method. +

+

+ If you do use one or more {@link android.support.v4.app.Fragment} objects in an + {@link android.app.Activity}, the {@link android.support.v4.app.LoaderManager} you retrieve is + available to all of them. +

+

Extend an Activity

+

+ To set up an {@link android.app.Activity} subclass to contain a + {@link android.support.v4.content.CursorLoader}, extend the subclass with + must extend {@link android.support.v4.app.FragmentActivity}, which provides the loader + framework, and implement the {@link android.support.v4.app.LoaderManager.LoaderCallbacks + LoaderCallbacks<Cursor>} interface, which specifies method signatures that the loader + framework uses to interact with the {@link android.app.Activity}. +

+

+ For example: +

+
+public class DisplayActivity extends FragmentActivity
+        implements LoaderManager.LoaderCallbacks<Cursor>
+
+

Retrieve a LoaderManager

+

+ To get an instance {@link android.support.v4.app.LoaderManager} for use in your + {@link android.app.Activity}, call + {@link android.support.v4.app.FragmentActivity#getSupportLoaderManager + FragmentActivity.getSupportLoaderManager()} at the beginning of the + {@link android.app.Activity#onCreate onCreate()} method. For example: +

+
+private LoaderManager mLoaderManager;
+public void onCreate() {
+...
+mLoaderManager = this.getSupportLoaderManager();
+
+

Initialize the Loader Framework

+

+ Once you have the {@link android.support.v4.app.LoaderManager} object, initialize + it by calling {@link android.support.v4.app.LoaderManager#initLoader initLoader()}. For + example: +

+
+// CursorLoader instance identifier
+public static final int URL_LOADER = 0;
+...
+// Initializes the CursorLoader
+getSupportLoaderManager().initLoader(URL_LOADER, null, this);
+
diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs index 4a5b0fadc5dd..1c85ae840188 100644 --- a/docs/html/training/training_toc.cs +++ b/docs/html/training/training_toc.cs @@ -58,7 +58,7 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + + -- cgit v1.2.3-59-g8ed1b