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 0000000000000..ce0024f031c26 --- /dev/null +++ b/docs/html/training/load-data-background/handle-results.jd @@ -0,0 +1,137 @@ +page.title=Handling the Results +trainingnavtop=true +startpage=true + +@jd:body + + +
+
+

This lesson teaches you to

+
    +
  1. + Handle Query Results +
  2. +
  3. + Delete Old Cursor References
  4. +
+ +

Try it out

+
+ Download the sample +

ThreadSample.zip

+
+ +
+
+ +

+ As shown in the previous lesson, you should begin loading your data with a + {@link android.support.v4.content.CursorLoader} in your implementation of + {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onCreateLoader + onCreateLoader()}. The loader then provides the query results to your + {@link android.app.Activity} or {@link android.support.v4.app.FragmentActivity} in your + implementation of {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoadFinished + LoaderCallbacks.onLoadFinished()}. One of the incoming arguments to this method is a + {@link android.database.Cursor} containing the query results. You can use this object to + update your data display or do further processing. +

+

+ Besides + {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()} and + {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()}, + you also have to implement + {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoaderReset onLoaderReset()}. + This method is invoked when {@link android.support.v4.content.CursorLoader} detects + that data associated with the {@link android.database.Cursor} has changed. When the + data changes, the framework also re-runs the current query. +

+

Handle Query Results

+

+ To display {@link android.database.Cursor} data returned by + {@link android.support.v4.content.CursorLoader}, use a + {@link android.view.View} class that implements {@link android.widget.AdapterView} and + provide the view with an adapter that implements + {@link android.support.v4.widget.CursorAdapter}. The system then automatically moves data from + the {@link android.database.Cursor} to the view. +

+

+ You can set up the linkage between the view and adapter before you have any data to display, + and then move a {@link android.database.Cursor} into the adapter in the + {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()} + method. As soon as you move the {@link android.database.Cursor} into the adapter, the + system automatically updates the view. This also happens if you change the contents of the + {@link android.database.Cursor}. +

+

+ For example: +

+
+public String[] mFromColumns = {
+    DataProviderContract.IMAGE_PICTURENAME_COLUMN
+};
+public int[] mToFields = {
+    R.id.PictureName
+};
+// Gets a handle to a List View
+ListView mListView = (ListView) findViewById(R.id.dataList);
+/*
+ * Defines a SimpleCursorAdapter for the ListView
+ *
+ */
+SimpleCursorAdapter mAdapter =
+    new SimpleCursorAdapter(
+            this,                // Current context
+            R.layout.list_item,  // Layout for a single row
+            null,                // No Cursor yet
+            mFromColumns,        // Cursor columns to use
+            mToFields,           // Layout fields to use
+            0                    // No flags
+    );
+// Sets the adapter for the view
+mListView.setAdapter(mAdapter);
+...
+/*
+ * Defines the callback that {@link android.support.v4.content.CursorLoader} calls
+ * when it's finished its query
+ */
+@Override
+public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
+    ...
+    /*
+     * Moves the query results into the adapter, causing the
+     * ListView fronting this adapter to re-display
+     */
+    mAdapter.changeCursor(cursor);
+}
+
+

Delete Old Cursor References

+

+ The {@link android.support.v4.content.CursorLoader} is reset whenever its + {@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, you should delete all references to the current {@link android.database.Cursor} + in order to prevent memory leaks. Once + {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoaderReset onLoaderReset()} + finishes, {@link android.support.v4.content.CursorLoader} re-runs its query. +

+

+ For example: +

+
+/*
+ * Invoked when the CursorLoader is being reset. For example, this is
+ * called if the data in the provider changes and the Cursor becomes stale.
+ */
+@Override
+public void onLoaderReset(Loader<Cursor> loader) {
+    
+    /*
+     * Clears out the adapter's reference to the Cursor.
+     * This prevents memory leaks.
+     */
+    mAdapter.changeCursor(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 0000000000000..dc9d84af7dd9f --- /dev/null +++ b/docs/html/training/load-data-background/index.jd @@ -0,0 +1,77 @@ +page.title=Loading Data in the Background +trainingnavtop=true +startpage=true + +@jd:body +
+
+ + +

Dependencies and prerequisites

+ + + +

You should also read

+ + +

Try it out

+
+ Download the sample +

ThreadSample.zip

+
+ +
+
+

+ Querying a {@link android.content.ContentProvider} for data you want to display takes time. + If you run the query directly from an {@link android.app.Activity}, it may get blocked and + cause the system to issue an "Application Not Responding" message. Even if it doesn't, users + will see an annoying delay in the UI. To avoid these problems, you should initiate a query on a + separate thread, wait for it to finish, and then display the results. +

+

+ You can do this in a straightforward way by using an object that runs a query asynchronously in + the background and reconnects to your {@link android.app.Activity} when it's finished. This + object is a {@link android.support.v4.content.CursorLoader}. Besides doing the initial + background query, a {@link android.support.v4.content.CursorLoader} automatically re-runs the + query when data associated with the query changes. +

+

+ This class describes how to use a {@link android.support.v4.content.CursorLoader} to run a + background query. 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

+
+
+ Running a Query with a CursorLoader +
+
+ Learn how to run a query in the background, 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 0000000000000..17fe7b0ea890c --- /dev/null +++ b/docs/html/training/load-data-background/setup-loader.jd @@ -0,0 +1,142 @@ +page.title=Running a Query with a CursorLoader +trainingnavtop=true +startpage=true + +@jd:body + + +
+
+

This lesson teaches you to

+
    +
  1. + Define an Activity That Uses CursorLoader +
  2. +
  3. + Initialize the Query +
  4. +
  5. + Start the Query +
  6. +
+ +

Try it out

+
+ Download the sample +

ThreadSample.zip

+
+ +
+
+

+ A {@link android.support.v4.content.CursorLoader} runs an asynchronous query in the background + against a {@link android.content.ContentProvider}, and returns the results to the + {@link android.app.Activity} or {@link android.support.v4.app.FragmentActivity} from which it + was called. This allows the {@link android.app.Activity} or + {@link android.support.v4.app.FragmentActivity} to continue to interact with the user while the + query is ongoing. +

+

Define an Activity That Uses CursorLoader

+

+ To use a {@link android.support.v4.content.CursorLoader} with an + {@link android.app.Activity} or {@link android.support.v4.app.FragmentActivity}, use the + {@link android.support.v4.app.LoaderManager.LoaderCallbacks LoaderCallbacks<Cursor>} + interface. A {@link android.support.v4.content.CursorLoader} invokes callbacks defined + in this interface to communicate with the class; this lesson and the next one + describe each callback in detail. +

+

+ For example, this is how you should define a {@link android.support.v4.app.FragmentActivity} + that uses the support library version of {@link android.support.v4.content.CursorLoader}. By + extending {@link android.support.v4.app.FragmentActivity}, you get support for + {@link android.support.v4.content.CursorLoader} as well as + {@link android.support.v4.app.Fragment}: +

+
+public class PhotoThumbnailFragment extends FragmentActivity implements
+        LoaderManager.LoaderCallbacks<Cursor> {
+...
+}
+
+

Initialize the Query

+

+ To initialize a query, call + {@link android.support.v4.app.LoaderManager#initLoader LoaderManager.initLoader()}. This + initializes the background framework. You can do this after the user has entered data that's + used in the query, or, if you don't need any user data, you can do it in + {@link android.support.v4.app.FragmentActivity#onCreate onCreate()} or + {@link android.support.v4.app.Fragment#onCreateView onCreateView()}. For example: +

+
+    // Identifies a particular Loader being used in this component
+    private static final int URL_LOADER = 0;
+    ...
+    /* When the system is ready for the Fragment to appear, this displays
+     * the Fragment's View
+     */
+    public View onCreateView(
+            LayoutInflater inflater,
+            ViewGroup viewGroup,
+            Bundle bundle) {
+        ...
+        /*
+         * Initializes the CursorLoader. The URL_LOADER value is eventually passed
+         * to onCreateLoader().
+         */
+        getLoaderManager().initLoader(URL_LOADER, null, this);
+        ...
+    }
+
+

+ Note: The method {@link android.support.v4.app.Fragment#getLoaderManager + getLoaderManager()} is only available in the {@link android.support.v4.app.Fragment} class. To + get a {@link android.support.v4.app.LoaderManager} in a + {@link android.support.v4.app.FragmentActivity}, call + {@link android.support.v4.app.FragmentActivity#getSupportLoaderManager + getSupportLoaderManager()}. +

+

Start the Query

+

+ As soon as the background framework is initialized, it calls your implementation of + {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()}. + To start the query, return a {@link android.support.v4.content.CursorLoader} from this method. + You can instantiate an empty {@link android.support.v4.content.CursorLoader} and then use its + methods to define your query, or you can instantiate the object and define the query at the + same time: +

+
+/*
+* Callback that's invoked when the system has initialized the Loader and
+* is ready to start the query. This usually happens when initLoader() is
+* called. The loaderID argument contains the ID value passed to the
+* initLoader() call.
+*/
+@Override
+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:
+            // Returns a new CursorLoader
+            return new CursorLoader(
+                        getActivity(),   // Parent activity context
+                        mDataUrl,        // Table to query
+                        mProjection,     // Projection to return
+                        null,            // No selection clause
+                        null,            // No selection arguments
+                        null             // Default sort order
+        );
+        default:
+            // An invalid id was passed in
+            return null;
+    }
+}
+
+

+ Once the background framework has the object, it starts the query in the background. When the + query is done, the background framework calls + {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()}, + which is described in the next lesson. +

diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs index 0f6994ebcc922..77909b8dbd0c7 100644 --- a/docs/html/training/training_toc.cs +++ b/docs/html/training/training_toc.cs @@ -1028,8 +1028,6 @@ - -