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

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

am bd9d92b6: am 5e1f7f08: am 2fc4182b: am 3252eb96: am cad9660f: am 7eef172e:...

am bd9d92b6: am 5e1f7f08: am 2fc4182b: am 3252eb96: am cad9660f: am 7eef172e: am ba34f097: Android Training: Loading Data in the Background

* commit 'bd9d92b6':
  Android Training: Loading Data in the Background
parents 3604e037 bd9d92b6
Loading
Loading
Loading
Loading
+137 −0
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">Delete Old Cursor References</a></li>
</ol>

<h2>Try it out</h2>
<div class="download-box">
    <a href="{@docRoot}shareables/training/ThreadSample.zip" class="button">Download the sample</a>
    <p class="filename">ThreadSample.zip</p>
</div>

  </div>
</div>

<p>
    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.
</p>
<p>
    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.
</p>
<h2 id="HandleResults">Handle Query Results</h2>
<p>
    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.
</p>
<p>
    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}.
</p>
<p>
    For example:
</p>
<pre>
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
 */
&#64;Override
public void onLoadFinished(Loader&lt;Cursor&gt; loader, Cursor cursor) {
    ...
    /*
     * Moves the query results into the adapter, causing the
     * ListView fronting this adapter to re-display
     */
    mAdapter.changeCursor(cursor);
}
</pre>
<h2 id="HandleReset">Delete Old Cursor References</h2>
<p>
    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.
</p>
<p>
    For example:
</p>
<pre>
/*
 * Invoked when the CursorLoader is being reset. For example, this is
 * called if the data in the provider changes and the Cursor becomes stale.
 */
&#64;Override
public void onLoaderReset(Loader&lt;Cursor&gt; loader) {
    
    /*
     * Clears out the adapter's reference to the Cursor.
     * This prevents memory leaks.
     */
    mAdapter.changeCursor(null);
}
</pre>
+77 −0
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>
<ul>
    <li>
        Android 1.6 or later
    </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>

<h2>Try it out</h2>
<div class="download-box">
    <a href="{@docRoot}shareables/training/ThreadSample.zip" class="button">Download the sample</a>
    <p class="filename">ThreadSample.zip</p>
</div>

</div>
</div>
<p>
    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.
</p>
<p>
    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.
</p>
<p>
    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.
</p>
<h2>Lessons</h2>
<dl>
    <dt>
        <strong><a href="setup-loader.html">Running a Query with a CursorLoader</a></strong>
    </dt>
    <dd>
        Learn how to run a query in the background, 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>
+142 −0
Original line number Diff line number Diff line
page.title=Running a Query with a CursorLoader
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="#Extend">Define an Activity That Uses CursorLoader</a>
    </li>
    <li>
        <a href="#InitializeLoader">Initialize the Query</a>
    </li>
    <li>
        <a href="#DefineLaunch">Start the Query</a>
    </li>
</ol>

<h2>Try it out</h2>
<div class="download-box">
    <a href="{@docRoot}shareables/training/ThreadSample.zip" class="button">Download the sample</a>
    <p class="filename">ThreadSample.zip</p>
</div>

  </div>
</div>
<p>
    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.
</p>
<h2 id="Extend">Define an Activity That Uses CursorLoader</h2>
<p>
    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&lt;Cursor&gt;}
    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.
</p>
<p>
    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}:
</p>
<pre>
public class PhotoThumbnailFragment extends FragmentActivity implements
        LoaderManager.LoaderCallbacks&lt;Cursor&gt; {
...
}
</pre>
<h2 id="InitializeLoader">Initialize the Query</h2>
<p>
    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:
</p>
<pre>
    // 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);
        ...
    }
</pre>
<p class="note">
    <strong>Note:</strong> 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()}.
</p>
<h2 id="DefineLaunch">Start the Query</h2>
<p>
    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:
</p>
<pre>
/*
* 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.
*/
&#64;Override
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:
            // 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;
    }
}
</pre>
<p>
    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.
</p>
+0 −3
Original line number Diff line number Diff line
@@ -1028,8 +1028,6 @@
          </li>
        </ul>
      </li>
      
      
      <li class="nav-section">
        <div class="nav-section-header">
          <a href="<?cs var:toroot ?>training/monetization/index.html"
@@ -1050,7 +1048,6 @@
  <!-- End best Publishing -->

</ul><!-- nav -->

<script type="text/javascript">
<!--
    buildToggleLists();