Skip to content

Commit fbcfb5d

Browse files
Joe MalinAndroid Git Automerger
authored andcommitted
am 50c2275: Android Training: CursorLoader
* commit '50c2275cff28c4a216f6924584e43cd64b90a3bf': Android Training: CursorLoader
2 parents a295ba4 + 50c2275 commit fbcfb5d

File tree

5 files changed

+435
-22
lines changed

5 files changed

+435
-22
lines changed
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
page.title=Defining and Launching the Query
2+
trainingnavtop=true
3+
startpage=true
4+
5+
@jd:body
6+
7+
<!-- This is the training bar -->
8+
<div id="tb-wrapper">
9+
<div id="tb">
10+
<h2>This lesson teaches you to</h2>
11+
<ol>
12+
<li>
13+
<a href="#DefineLaunch">Define and Launch the Query</a>
14+
</li>
15+
</ol>
16+
</div>
17+
</div>
18+
19+
<p>
20+
To perform a query, create the {@link android.support.v4.content.CursorLoader}, set up its
21+
query, and pass it to the loader framework. From then on, the framework manages everything.
22+
It runs the query on a background thread, returns the results to the foreground, and
23+
watches for changes to the data associated with the query.
24+
</p>
25+
<p>
26+
Pass a {@link android.support.v4.content.CursorLoader} to the loader framework in
27+
your implementation of
28+
{@link android.support.v4.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()}.
29+
The loader framework calls this method when you <i>create</i> a loader by calling
30+
{@link android.support.v4.app.LoaderManager#initLoader initLoader()}. You can create
31+
a {@link android.support.v4.content.CursorLoader} anywhere,
32+
but the preferred way is to create it in
33+
{@link android.support.v4.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()},
34+
because this defers creation until the object is actually needed.
35+
</p>
36+
<p>
37+
Notice that {@link android.support.v4.app.LoaderManager#initLoader initLoader()} will only
38+
{@link android.support.v4.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()}
39+
if the {@link android.support.v4.content.CursorLoader} doesn't already exist; otherwise, it
40+
re-uses the existing {@link android.support.v4.content.CursorLoader}. The loader framework
41+
tracks {@link android.support.v4.content.CursorLoader} instance using the <code>id</code>
42+
value passed to {@link android.support.v4.app.LoaderManager#initLoader initLoader()}.
43+
</p>
44+
<h2 id="DefineLaunch">Define and Launch the Query</h2>
45+
<p>
46+
To create a {@link android.support.v4.content.CursorLoader} and define its
47+
query at the same time, call the constructor
48+
{@link android.support.v4.content.CursorLoader#CursorLoader(Context, Uri, String[], String, String[], String)
49+
CursorLoader(context, uri, projection, selection, selectionArgs, sortOrder)}. The
50+
<code>context</code> and <code>uri</code> arguments are required, but the others are optional.
51+
To use the default value for an optional argument, pass in <code>null</code>. The
52+
{@link android.support.v4.content.CursorLoader} runs the query against the
53+
{@link android.content.ContentProvider} identified by <code>uri</code>, just as if you had
54+
called {@link android.content.ContentResolver#query ContentResolver.query()} with the same
55+
arguments.
56+
</p>
57+
<p>
58+
For example:
59+
</p>
60+
<pre>
61+
public Loader&lt;Cursor&gt; onCreateLoader(int loaderID, Bundle bundle)
62+
{
63+
/*
64+
* Takes action based on the ID of the Loader that's being created
65+
*/
66+
switch (loaderID) {
67+
case URL_LOADER:
68+
/*
69+
* Return a new CursorLoader
70+
*/
71+
return new CursorLoader(
72+
this, // Context
73+
DataProviderContract.IMAGE_URI, // Provider's content URI
74+
PROJECTION, // Columns to return
75+
null, // Return all rows
76+
null, // No search arguments
77+
null); // Default search order
78+
default:
79+
// An invalid id was passed in
80+
return null;
81+
}
82+
}
83+
</pre>
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
page.title=Handling the Results
2+
trainingnavtop=true
3+
startpage=true
4+
5+
@jd:body
6+
7+
<!-- This is the training bar -->
8+
<div id="tb-wrapper">
9+
<div id="tb">
10+
<h2>This lesson teaches you to</h2>
11+
<ol>
12+
<li>
13+
<a href="#HandleResults">Handle Query Results</a>
14+
</li>
15+
<li>
16+
<a href="#HandleReset">Clear Out Old Data</a></li>
17+
</ol>
18+
</div>
19+
</div>
20+
21+
<p>
22+
{@link android.support.v4.content.CursorLoader} returns its query results to your
23+
implementation of
24+
{@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoadFinished
25+
LoaderCallbacks.onLoadFinished()}, in the form of a {@link android.database.Cursor}. In the
26+
callback, you can update your data display, do further processing on the
27+
{@link android.database.Cursor} data, and so forth.
28+
</p>
29+
<p>
30+
When the loader framework detects changes to data associated with the query,
31+
it resets the {@link android.support.v4.content.CursorLoader}, closes the current
32+
{@link android.database.Cursor}, and then invokes your implementation of
33+
{@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoaderReset onLoaderReset()}.
34+
Use this callback to delete references to the current {@link android.database.Cursor}; when the
35+
loader framework destroys the {@link android.database.Cursor}, you won't have outstanding
36+
references that cause memory leaks.
37+
</p>
38+
<h2 id="HandleFinished">Handle Query Results</h2>
39+
<p>
40+
The following two snippets are an example of displaying the results of a query, using a
41+
{@link android.widget.ListView} backed by a
42+
{@link android.support.v4.widget.SimpleCursorAdapter}.
43+
</p>
44+
<p>
45+
The first snippet shows the {@link android.widget.ListView} and
46+
{@link android.support.v4.widget.SimpleCursorAdapter}:
47+
</p>
48+
<pre>
49+
// Gets a handle to the Android built-in ListView widget
50+
mListView = ((ListView) findViewById(android.R.id.list));
51+
// Creates a CursorAdapter
52+
mAdapter =
53+
new SimpleCursorAdapter(
54+
this, // Current context
55+
R.layout.logitem, // View for each item in the list
56+
null, // Don't provide the cursor yet
57+
FROM_COLUMNS, // List of cursor columns to display
58+
TO_FIELDS, // List of TextViews in each line
59+
0 // flags
60+
);
61+
// Links the adapter to the ListView
62+
mListView.setAdapter(mAdapter);
63+
</pre>
64+
<p>
65+
The next snippet shows an implementation of
66+
{@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()}
67+
that moves the query results in the returned {@link android.database.Cursor} to the
68+
{@link android.support.v4.widget.SimpleCursorAdapter}. Changing the
69+
{@link android.database.Cursor} in the
70+
{@link android.support.v4.widget.SimpleCursorAdapter} triggers a refresh of the
71+
{@link android.widget.ListView} with the new data:
72+
</p>
73+
<pre>
74+
public void onLoadFinished(Loader&lt;Cursor&gt; loader, Cursor cursor)
75+
{
76+
/*
77+
* Move the results into the adapter. This
78+
* triggers the ListView to re-display.
79+
*/
80+
mAdapter.swapCursor(cursor);
81+
}
82+
</pre>
83+
<h2 id="HandleReset">Handle a Loader Reset</h2>
84+
<p>
85+
The loader framework resets the {@link android.support.v4.content.CursorLoader} whenever the
86+
{@link android.database.Cursor} becomes invalid. This usually occurs because the data associated
87+
with the {@link android.database.Cursor} has changed. Before re-running the query,
88+
the framework calls your implementation of
89+
{@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoaderReset onLoaderReset()}. In
90+
this callback, make sure to prevent memory leaks by deleting all references to the current
91+
{@link android.database.Cursor}. Once you return from
92+
{@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoaderReset onLoaderReset()},
93+
the loader framework re-runs the query.
94+
</p>
95+
<p>
96+
For example:
97+
</p>
98+
<pre>
99+
public void onLoaderReset(Loader&lt;Cursor&gt; loader)
100+
{
101+
// Remove the reference to the current Cursor
102+
mAdapter.swapCursor(null);
103+
}
104+
</pre>
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
page.title=Loading Data in the Background
2+
trainingnavtop=true
3+
startpage=true
4+
5+
@jd:body
6+
<div id="tb-wrapper">
7+
<div id="tb">
8+
9+
<!-- Required platform, tools, add-ons, devices, knowledge, etc. -->
10+
<h2>Dependencies and prerequisites</h2>
11+
<h3>Dependencies</h3>
12+
<ul>
13+
<li>
14+
Android 1.6 or later
15+
</li>
16+
</ul>
17+
<h3>Prerequisites</h3>
18+
<ul>
19+
<li>
20+
<a href="{@docRoot}training/basics/firstapp/index.html">Building Your First App</a> class
21+
</li>
22+
<li>
23+
<a href="{@docRoot}training/basics/activity-lifecycle/index.html">
24+
Managing the Activity Lifecycle</a> class
25+
</li>
26+
</ul>
27+
28+
<!-- related docs (NOT javadocs) -->
29+
<h2>You should also read</h2>
30+
<ul>
31+
<li>
32+
<a href="{@docRoot}guide/components/loaders.html">Loaders</a>
33+
</li>
34+
<li>
35+
<a href="{@docRoot}guide/topics/data/data-storage.html#db">Using Databases</a>
36+
</li>
37+
<li>
38+
<a href="{@docRoot}guide/topics/providers/content-provider-basics.html">Content Provider Basics</a>
39+
</li>
40+
</ul>
41+
</div>
42+
</div>
43+
<p>
44+
A {@link android.support.v4.content.CursorLoader} runs a query against a
45+
{@link android.content.ContentProvider} on a background thread and returns a
46+
{@link android.database.Cursor} to the main thread.
47+
</p>
48+
<p>
49+
{@link android.support.v4.content.CursorLoader} has these advantages over alternate ways of
50+
running a query:
51+
</p>
52+
<dl>
53+
<dt>
54+
Query on a background thread
55+
</dt>
56+
<dd>
57+
A {@link android.support.v4.content.CursorLoader} query runs asynchronously on a
58+
background thread, so it doesn't cause "Application Not Responding" (ANR) errors on the UI
59+
thread. {@link android.support.v4.content.CursorLoader} creates and starts the
60+
background thread; all you have to do is initialize the loader framework and handle the
61+
results of the query.
62+
</dd>
63+
<dt>
64+
Automatic re-query
65+
</dt>
66+
<dd>
67+
A {@link android.support.v4.content.CursorLoader} automatically runs a new query when
68+
the loader framework detects that the data underlying the {@link android.database.Cursor}
69+
has changed.
70+
</dd>
71+
<dt>
72+
Simple API
73+
</dt>
74+
<dd>
75+
The {@link android.support.v4.content.CursorLoader} API provides the
76+
query framework and cursor monitoring that you would have to define yourself if you used
77+
{@link android.os.AsyncTask}.
78+
</dd>
79+
</dl>
80+
<p>
81+
A {@link android.support.v4.content.CursorLoader} is limited in that the query must be
82+
against a {@link android.net.Uri} and must return a {@link android.database.Cursor}. Because of
83+
this, a {@link android.support.v4.content.CursorLoader} can only run a query against a
84+
{@link android.content.ContentProvider}.
85+
</p>
86+
<p>
87+
This class describes how to define and use a {@link android.support.v4.content.CursorLoader}.
88+
Examples in this class use the {@link android.support.v4 v4 support library} versions of
89+
classes, which support platforms starting with Android 1.6.
90+
</p>
91+
<h2>Lessons</h2>
92+
<dl>
93+
<dt>
94+
<strong><a href="setup-loader.html">Setting Up the Loader</a></strong>
95+
</dt>
96+
<dd>
97+
Learn how to set up an {@link android.app.Activity} that inherits the necessary classes
98+
for running a {@link android.support.v4.content.CursorLoader} and returning results.
99+
</dd>
100+
<dt>
101+
<strong><a href="define-launch-query.html">Defining and Launching the Query</a></strong>
102+
</dt>
103+
<dd>
104+
Learn how to perform a query against a {@link android.content.ContentProvider} using
105+
a {@link android.support.v4.content.CursorLoader}.
106+
</dd>
107+
<dt>
108+
<strong>
109+
<a href="handle-results.html">Handling the Results</a>
110+
</strong>
111+
</dt>
112+
<dd>
113+
Learn how to handle the {@link android.database.Cursor} returned from the query, and how
114+
to remove references to the current {@link android.database.Cursor} when the loader
115+
framework re-sets the {@link android.support.v4.content.CursorLoader}.
116+
</dd>
117+
</dl>
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
page.title=Setting Up the Loader
2+
trainingnavtop=true
3+
startpage=true
4+
5+
@jd:body
6+
7+
<!-- This is the training bar -->
8+
<div id="tb-wrapper">
9+
<div id="tb">
10+
<h2>This lesson teaches you to</h2>
11+
<ol>
12+
<li>
13+
<a href="#AddExtensions">Extend an Activity</a>
14+
</li>
15+
<li>
16+
<a href="#GetLoader">Retrieve a LoaderManager</a>
17+
</li>
18+
<li>
19+
<a href="#InitializeLoader">Initialize the Loader Framework</a>
20+
</li>
21+
</ol>
22+
</div>
23+
</div>
24+
<p>
25+
You create a {@link android.support.v4.content.CursorLoader} within a
26+
<b>loader framework</b>. To set up the framework, you implement the
27+
{@link android.support.v4.app.LoaderManager.LoaderCallbacks LoaderCallbacks&lt;Cursor&gt;}
28+
as part of an {@link android.app.Activity}. In addition, to provide compatibility
29+
compatible with platform versions starting with Android 1.6, you must extend the
30+
{@link android.app.Activity} with the {@link android.support.v4.app.FragmentActivity} class.
31+
</p>
32+
<p class="note">
33+
<strong>Note:</strong> A {@link android.support.v4.app.Fragment} is not a prerequisite for
34+
{@link android.support.v4.content.CursorLoader}. As a convenience, the support library class
35+
{@link android.support.v4.app.FragmentActivity} contains the fragment and the loader frameworks,
36+
but they are completely independent of each other.
37+
</p>
38+
<p>
39+
Before you can use the loader framework, you need to initialize it. To do this, retrieve
40+
a {@link android.support.v4.app.LoaderManager} object and call its
41+
{@link android.support.v4.app.LoaderManager#initLoader initLoader()} method.
42+
</p>
43+
<p>
44+
If you do use one or more {@link android.support.v4.app.Fragment} objects in an
45+
{@link android.app.Activity}, the {@link android.support.v4.app.LoaderManager} you retrieve is
46+
available to all of them.
47+
</p>
48+
<h2 id="AddExtensions">Extend an Activity</h2>
49+
<p>
50+
To set up an {@link android.app.Activity} subclass to contain a
51+
{@link android.support.v4.content.CursorLoader}, extend the subclass with
52+
must extend {@link android.support.v4.app.FragmentActivity}, which provides the loader
53+
framework, and implement the {@link android.support.v4.app.LoaderManager.LoaderCallbacks
54+
LoaderCallbacks&lt;Cursor&gt;} interface, which specifies method signatures that the loader
55+
framework uses to interact with the {@link android.app.Activity}.
56+
</p>
57+
<p>
58+
For example:
59+
</p>
60+
<pre>
61+
public class DisplayActivity extends FragmentActivity
62+
implements LoaderManager.LoaderCallbacks&lt;Cursor&gt;
63+
</pre>
64+
<h2 id="GetLoader">Retrieve a LoaderManager</h2>
65+
<p>
66+
To get an instance {@link android.support.v4.app.LoaderManager} for use in your
67+
{@link android.app.Activity}, call
68+
{@link android.support.v4.app.FragmentActivity#getSupportLoaderManager
69+
FragmentActivity.getSupportLoaderManager()} at the beginning of the
70+
{@link android.app.Activity#onCreate onCreate()} method. For example:
71+
</p>
72+
<pre>
73+
private LoaderManager mLoaderManager;
74+
public void onCreate() {
75+
...
76+
mLoaderManager = this.getSupportLoaderManager();
77+
</pre>
78+
<h2 id="InitializeLoader">Initialize the Loader Framework</h2>
79+
<p>
80+
Once you have the {@link android.support.v4.app.LoaderManager} object, initialize
81+
it by calling {@link android.support.v4.app.LoaderManager#initLoader initLoader()}. For
82+
example:
83+
</p>
84+
<pre>
85+
// CursorLoader instance identifier
86+
public static final int URL_LOADER = 0;
87+
...
88+
// Initializes the CursorLoader
89+
getSupportLoaderManager().initLoader(URL_LOADER, null, this);
90+
</pre>

0 commit comments

Comments
 (0)