Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4f7bf6ea authored by Joe Malin's avatar Joe Malin Committed by Android Git Automerger
Browse files

am 0b7d87cb: am 803abe6e: am 35ef45a7: am 28cb6150: am 7096a17e: am 718c7484:...

am 0b7d87cb: am 803abe6e: am 35ef45a7: am 28cb6150: am 7096a17e: am 718c7484: am f0f5efbe: Android Training: Run in a Background Service

* commit '0b7d87cb':
  Android Training: Run in a Background Service
parents 3366cb2a 0b7d87cb
Loading
Loading
Loading
Loading
+73.4 KiB

File added.

No diff preview for this file type.

+0 −83
Original line number Diff line number Diff line
page.title=Defining and Launching the Query
trainingnavtop=true
startpage=true

@jd:body

<!-- This is the training bar -->
<div id="tb-wrapper">
  <div id="tb">
<h2>This lesson teaches you to</h2>
<ol>
    <li>
        <a href="#DefineLaunch">Define and Launch the Query</a>
    </li>
</ol>
  </div>
</div>

<p>
    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.
</p>
<p>
    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 <i>create</i> 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.
</p>
<p>
    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 <code>id</code>
    value passed to {@link android.support.v4.app.LoaderManager#initLoader initLoader()}.
</p>
<h2 id="DefineLaunch">Define and Launch the Query</h2>
<p>
    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
    <code>context</code> and <code>uri</code> arguments are required, but the others are optional.
    To use the default value for an optional argument, pass in <code>null</code>. The
    {@link android.support.v4.content.CursorLoader} runs the query against the
    {@link android.content.ContentProvider} identified by <code>uri</code>, just as if you had
    called {@link android.content.ContentResolver#query ContentResolver.query()} with the same
    arguments.
</p>
<p>
    For example:
</p>
<pre>
public Loader&lt;Cursor&gt; 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;
    }
}
</pre>
+0 −104
Original line number Diff line number Diff line
page.title=Handling the Results
trainingnavtop=true
startpage=true

@jd:body

<!-- This is the training bar -->
<div id="tb-wrapper">
  <div id="tb">
<h2>This lesson teaches you to</h2>
<ol>
  <li>
    <a href="#HandleResults">Handle Query Results</a>
  </li>
  <li>
    <a href="#HandleReset">Clear Out Old Data</a></li>
</ol>
  </div>
</div>

<p>
    {@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.
</p>
<p>
    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.
</p>
<h2 id="HandleFinished">Handle Query Results</h2>
<p>
    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}.
</p>
<p>
    The first snippet shows the {@link android.widget.ListView} and
    {@link android.support.v4.widget.SimpleCursorAdapter}:
</p>
<pre>
// 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);
</pre>
<p>
    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:
</p>
<pre>
public void onLoadFinished(Loader&lt;Cursor&gt; loader, Cursor cursor)
{
    /*
     * Move the results into the adapter. This
     * triggers the ListView to re-display.
     */
    mAdapter.swapCursor(cursor);
}
</pre>
<h2 id="HandleReset">Handle a Loader Reset</h2>
<p>
    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.
</p>
<p>
    For example:
</p>
<pre>
public void onLoaderReset(Loader&lt;Cursor&gt; loader)
{
    // Remove the reference to the current Cursor
    mAdapter.swapCursor(null);
}
</pre>
+0 −117
Original line number Diff line number Diff line
page.title=Loading Data in the Background
trainingnavtop=true
startpage=true

@jd:body
<div id="tb-wrapper">
<div id="tb">

<!-- Required platform, tools, add-ons, devices, knowledge, etc. -->
<h2>Dependencies and prerequisites</h2>
<h3>Dependencies</h3>
<ul>
    <li>
        Android 1.6 or later
    </li>
</ul>
<h3>Prerequisites</h3>
<ul>
    <li>
        <a href="{@docRoot}training/basics/firstapp/index.html">Building Your First App</a> class
    </li>
    <li>
        <a href="{@docRoot}training/basics/activity-lifecycle/index.html">
        Managing the Activity Lifecycle</a> class
    </li>
</ul>

<!-- related docs (NOT javadocs) -->
<h2>You should also read</h2>
<ul>
    <li>
        <a href="{@docRoot}guide/components/loaders.html">Loaders</a>
    </li>
    <li>
        <a href="{@docRoot}guide/topics/data/data-storage.html#db">Using Databases</a>
    </li>
    <li>
<a href="{@docRoot}guide/topics/providers/content-provider-basics.html">Content Provider Basics</a>
    </li>
</ul>
</div>
</div>
<p>
    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.
</p>
<p>
    {@link android.support.v4.content.CursorLoader} has these advantages over alternate ways of
    running a query:
</p>
<dl>
    <dt>
        Query on a background thread
    </dt>
    <dd>
        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.
    </dd>
    <dt>
        Automatic re-query
    </dt>
    <dd>
        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.
    </dd>
    <dt>
        Simple API
    </dt>
    <dd>
        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}.
    </dd>
</dl>
<p>
    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}.
</p>
<p>
    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.
</p>
<h2>Lessons</h2>
<dl>
    <dt>
        <strong><a href="setup-loader.html">Setting Up the Loader</a></strong>
    </dt>
    <dd>
        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.
    </dd>
    <dt>
        <strong><a href="define-launch-query.html">Defining and Launching the Query</a></strong>
    </dt>
    <dd>
        Learn how to perform a query against a {@link android.content.ContentProvider} using
        a {@link android.support.v4.content.CursorLoader}.
    </dd>
    <dt>
        <strong>
        <a href="handle-results.html">Handling the Results</a>
        </strong>
    </dt>
    <dd>
        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}.
    </dd>
</dl>
+0 −90
Original line number Diff line number Diff line
page.title=Setting Up the Loader
trainingnavtop=true
startpage=true

@jd:body

<!-- This is the training bar -->
<div id="tb-wrapper">
  <div id="tb">
<h2>This lesson teaches you to</h2>
<ol>
    <li>
        <a href="#AddExtensions">Extend an Activity</a>
    </li>
    <li>
        <a href="#GetLoader">Retrieve a LoaderManager</a>
    </li>
    <li>
        <a href="#InitializeLoader">Initialize the Loader Framework</a>
    </li>
</ol>
  </div>
</div>
<p>
    You create a {@link android.support.v4.content.CursorLoader} within a
    <b>loader framework</b>. To set up the framework, you implement the
    {@link android.support.v4.app.LoaderManager.LoaderCallbacks LoaderCallbacks&lt;Cursor&gt;}
    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.
</p>
<p class="note">
    <strong>Note:</strong> 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.
</p>
<p>
    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.
</p>
<p>
    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.
</p>
<h2 id="AddExtensions">Extend an Activity</h2>
<p>
    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&lt;Cursor&gt;} interface, which specifies method signatures that the loader
    framework uses to interact with the {@link android.app.Activity}.
</p>
<p>
    For example:
</p>
<pre>
public class DisplayActivity extends FragmentActivity
        implements LoaderManager.LoaderCallbacks&lt;Cursor&gt;
</pre>
<h2 id="GetLoader">Retrieve a LoaderManager</h2>
<p>
    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:
</p>
<pre>
private LoaderManager mLoaderManager;
public void onCreate() {
...
mLoaderManager = this.getSupportLoaderManager();
</pre>
<h2 id="InitializeLoader">Initialize the Loader Framework</h2>
<p>
    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:
</p>
<pre>
// CursorLoader instance identifier
public static final int URL_LOADER = 0;
...
// Initializes the CursorLoader
getSupportLoaderManager().initLoader(URL_LOADER, null, this);
</pre>
Loading