|  | page.title=Loaders | 
|  | parent.title=Activities | 
|  | parent.link=activities.html | 
|  | @jd:body | 
|  | <div id="qv-wrapper"> | 
|  | <div id="qv"> | 
|  | <h2>In this document</h2> | 
|  | <ol> | 
|  | <li><a href="#summary">Loader API Summary</a></li> | 
|  | <li><a href="#app">Using Loaders in an Application</a> | 
|  | <ol> | 
|  | <li><a href="#requirements"></a></li> | 
|  | <li><a href="#starting">Starting a Loader</a></li> | 
|  | <li><a href="#restarting">Restarting a Loader</a></li> | 
|  | <li><a href="#callback">Using the LoaderManager Callbacks</a></li> | 
|  | </ol> | 
|  | </li> | 
|  | <li><a href="#example">Example</a> | 
|  | <ol> | 
|  | <li><a href="#more_examples">More Examples</a></li> | 
|  | </ol> | 
|  | </li> | 
|  | </ol> | 
|  |  | 
|  | <h2>Key classes</h2> | 
|  | <ol> | 
|  | <li>{@link android.app.LoaderManager}</li> | 
|  | <li>{@link android.content.Loader}</li> | 
|  |  | 
|  | </ol> | 
|  |  | 
|  | <h2>Related samples</h2> | 
|  | <ol> | 
|  | <li> <a | 
|  | href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderCursor.html"> | 
|  | LoaderCursor</a></li> | 
|  | <li> <a | 
|  | href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderThrottle.html"> | 
|  | LoaderThrottle</a></li> | 
|  | </ol> | 
|  | </div> | 
|  | </div> | 
|  |  | 
|  | <p>Introduced in Android 3.0, loaders make it easy to asynchronously load data | 
|  | in an activity or fragment. Loaders have these characteristics:</p> | 
|  | <ul> | 
|  | <li>They are available to every {@link android.app.Activity} and {@link | 
|  | android.app.Fragment}.</li> | 
|  | <li>They provide asynchronous loading of data.</li> | 
|  | <li>They monitor the source of their data and deliver new results when the | 
|  | content changes.</li> | 
|  | <li>They automatically reconnect to the last loader's cursor when being | 
|  | recreated after a configuration change. Thus, they don't need to re-query their | 
|  | data.</li> | 
|  | </ul> | 
|  |  | 
|  | <h2 id="summary">Loader API Summary</h2> | 
|  |  | 
|  | <p>There are multiple classes and interfaces that may be involved in using | 
|  | loaders in an application. They are summarized in this table:</p> | 
|  |  | 
|  | <table> | 
|  | <tr> | 
|  | <th>Class/Interface</th> | 
|  | <th>Description</th> | 
|  | </tr> | 
|  | <tr> | 
|  | <td>{@link android.app.LoaderManager}</td> | 
|  | <td>An abstract class associated with an {@link android.app.Activity} or | 
|  | {@link android.app.Fragment} for managing one or more {@link | 
|  | android.content.Loader} instances. This helps an application manage | 
|  | longer-running operations in conjunction with the {@link android.app.Activity} | 
|  | or {@link android.app.Fragment} lifecycle; the most common use of this is with a | 
|  | {@link android.content.CursorLoader}, however applications are free to write | 
|  | their own loaders for loading other types of data. | 
|  | <br /> | 
|  | <br /> | 
|  | There is only one {@link android.app.LoaderManager} per activity or fragment. But a {@link android.app.LoaderManager} can have | 
|  | multiple loaders.</td> | 
|  | </tr> | 
|  | <tr> | 
|  | <td>{@link android.app.LoaderManager.LoaderCallbacks}</td> | 
|  | <td>A callback interface for a client to interact with the {@link | 
|  | android.app.LoaderManager}. For example, you use the {@link | 
|  | android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()} | 
|  | callback method to create a new loader.</td> | 
|  | </tr> | 
|  | <tr> | 
|  | <td>{@link android.content.Loader}</td> | 
|  | <td>An abstract class that performs asynchronous loading of data. This is | 
|  | the base class for a loader. You would typically use {@link | 
|  | android.content.CursorLoader}, but you can implement your own subclass. While | 
|  | loaders are active they should monitor the source of their data and deliver new | 
|  | results when the contents change. </td> | 
|  | </tr> | 
|  | <tr> | 
|  | <td>{@link android.content.AsyncTaskLoader}</td> | 
|  | <td>Abstract loader that provides an {@link android.os.AsyncTask} to do the work.</td> | 
|  | </tr> | 
|  | <tr> | 
|  | <td>{@link android.content.CursorLoader}</td> | 
|  | <td>A subclass of {@link android.content.AsyncTaskLoader} that queries the | 
|  | {@link android.content.ContentResolver} and returns a {@link | 
|  | android.database.Cursor}. This class implements the {@link | 
|  | android.content.Loader} protocol in a standard way for querying cursors, | 
|  | building on {@link android.content.AsyncTaskLoader} to perform the cursor query | 
|  | on a background thread so that it does not block the application's UI. Using | 
|  | this loader is the best way to asynchronously load data from a {@link | 
|  | android.content.ContentProvider}, instead of performing a managed query through | 
|  | the fragment or activity's APIs.</td> | 
|  | </tr> | 
|  | </table> | 
|  |  | 
|  | <p>The classes and interfaces in the above table are the essential components | 
|  | you'll use to implement a loader in your application. You won't need all of them | 
|  | for each loader you create, but you'll always need a reference to the {@link | 
|  | android.app.LoaderManager} in order to initialize a loader and an implementation | 
|  | of a {@link android.content.Loader} class such as {@link | 
|  | android.content.CursorLoader}. The following sections show you how to use these | 
|  | classes and interfaces in an application.</p> | 
|  |  | 
|  | <h2 id ="app">Using Loaders in an Application</h2> | 
|  | <p>This section describes how to use loaders in an Android application. An | 
|  | application that uses loaders typically includes the following:</p> | 
|  | <ul> | 
|  | <li>An {@link android.app.Activity} or {@link android.app.Fragment}.</li> | 
|  | <li>An instance of the {@link android.app.LoaderManager}.</li> | 
|  | <li>A {@link android.content.CursorLoader} to load data backed by a {@link | 
|  | android.content.ContentProvider}. Alternatively, you can implement your own subclass | 
|  | of {@link android.content.Loader} or {@link android.content.AsyncTaskLoader} to | 
|  | load data from some other source.</li> | 
|  | <li>An implementation for {@link android.app.LoaderManager.LoaderCallbacks}. | 
|  | This is where you create new loaders and manage your references to existing | 
|  | loaders.</li> | 
|  | <li>A way of displaying the loader's data, such as a {@link | 
|  | android.widget.SimpleCursorAdapter}.</li> | 
|  | <li>A data source, such as a {@link android.content.ContentProvider}, when using a | 
|  | {@link android.content.CursorLoader}.</li> | 
|  | </ul> | 
|  | <h3 id="starting">Starting a Loader</h3> | 
|  |  | 
|  | <p>The {@link android.app.LoaderManager} manages one or more {@link | 
|  | android.content.Loader} instances within an {@link android.app.Activity} or | 
|  | {@link android.app.Fragment}. There is only one {@link | 
|  | android.app.LoaderManager} per activity or fragment.</p> | 
|  |  | 
|  | <p>You typically | 
|  | initialize a {@link android.content.Loader} within the activity's {@link | 
|  | android.app.Activity#onCreate onCreate()} method, or within the fragment's | 
|  | {@link android.app.Fragment#onActivityCreated onActivityCreated()} method. You | 
|  | do this as follows:</p> | 
|  |  | 
|  | <pre>// Prepare the loader.  Either re-connect with an existing one, | 
|  | // or start a new one. | 
|  | getLoaderManager().initLoader(0, null, this);</pre> | 
|  |  | 
|  | <p>The {@link android.app.LoaderManager#initLoader initLoader()} method takes | 
|  | the following parameters:</p> | 
|  | <ul> | 
|  | <li>A unique ID that identifies the loader. In this example, the ID is 0.</li> | 
|  | <li>Optional arguments to supply to the loader at | 
|  | construction (<code>null</code> in this example).</li> | 
|  |  | 
|  | <li>A {@link android.app.LoaderManager.LoaderCallbacks} implementation, which | 
|  | the {@link android.app.LoaderManager} calls to report loader events. In this | 
|  | example, the local class implements the {@link | 
|  | android.app.LoaderManager.LoaderCallbacks} interface, so it passes a reference | 
|  | to itself, {@code this}.</li> | 
|  | </ul> | 
|  | <p>The {@link android.app.LoaderManager#initLoader initLoader()} call ensures that a loader | 
|  | is initialized and active. It has two possible outcomes:</p> | 
|  | <ul> | 
|  | <li>If the loader specified by the ID already exists, the last created loader | 
|  | is reused.</li> | 
|  | <li>If the loader specified by the ID does <em>not</em> exist, | 
|  | {@link android.app.LoaderManager#initLoader initLoader()} triggers the | 
|  | {@link android.app.LoaderManager.LoaderCallbacks} method {@link android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()}. | 
|  | This is where you  implement the code to instantiate and return a new loader. | 
|  | For more discussion, see the section <a | 
|  | href="#onCreateLoader">onCreateLoader</a>.</li> | 
|  | </ul> | 
|  | <p>In either case, the given {@link android.app.LoaderManager.LoaderCallbacks} | 
|  | implementation is associated with the loader, and  will be called when the | 
|  | loader state changes.  If at the point of this call  the caller is in its | 
|  | started state, and the requested loader already exists and has generated its | 
|  | data, then the system calls {@link | 
|  | android.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()} | 
|  | immediately (during {@link android.app.LoaderManager#initLoader initLoader()}), | 
|  | so you must be prepared for this to happen. See <a href="#onLoadFinished"> | 
|  | onLoadFinished</a> for more discussion of this callback</p> | 
|  |  | 
|  | <p>Note that the {@link android.app.LoaderManager#initLoader initLoader()} | 
|  | method returns the {@link android.content.Loader} that is created, but you don't | 
|  | need to capture a reference to it. The {@link android.app.LoaderManager} manages | 
|  | the life of the loader automatically. The {@link android.app.LoaderManager} | 
|  | starts and stops loading when necessary, and maintains the state of the loader | 
|  | and its associated content. As this implies, you rarely interact with loaders | 
|  | directly (though for an example of using loader methods to fine-tune a loader's | 
|  | behavior, see the <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderThrottle.html"> LoaderThrottle</a> sample). | 
|  | You most commonly use the {@link | 
|  | android.app.LoaderManager.LoaderCallbacks} methods to intervene in the loading | 
|  | process when particular events occur. For more discussion of this topic, see <a | 
|  | href="#callback">Using the LoaderManager Callbacks</a>.</p> | 
|  |  | 
|  | <h3 id="restarting">Restarting a Loader</h3> | 
|  |  | 
|  | <p>When you use {@link android.app.LoaderManager#initLoader initLoader()}, as | 
|  | shown above, it uses an existing loader with the specified ID if there is one. | 
|  | If there isn't, it creates one. But sometimes you want to discard your old data | 
|  | and start over.</p> | 
|  |  | 
|  | <p>To discard your old data, you use {@link | 
|  | android.app.LoaderManager#restartLoader restartLoader()}. For example, this | 
|  | implementation of {@link android.widget.SearchView.OnQueryTextListener} restarts | 
|  | the loader when the user's query changes. The loader needs to be restarted so | 
|  | that it can use the revised search filter to do a new query:</p> | 
|  |  | 
|  | <pre> | 
|  | public boolean onQueryTextChanged(String newText) { | 
|  | // Called when the action bar search text has changed.  Update | 
|  | // the search filter, and restart the loader to do a new query | 
|  | // with this filter. | 
|  | mCurFilter = !TextUtils.isEmpty(newText) ? newText : null; | 
|  | getLoaderManager().restartLoader(0, null, this); | 
|  | return true; | 
|  | }</pre> | 
|  |  | 
|  | <h3 id="callback">Using the LoaderManager Callbacks</h3> | 
|  |  | 
|  | <p>{@link android.app.LoaderManager.LoaderCallbacks} is a callback interface | 
|  | that lets a client  interact with the {@link android.app.LoaderManager}. </p> | 
|  | <p>Loaders, in particular {@link android.content.CursorLoader}, are  expected to | 
|  | retain their  data after being stopped. This allows applications to keep their | 
|  | data across the activity or fragment's {@link android.app.Activity#onStop | 
|  | onStop()} and {@link android.app.Activity#onStart onStart()} methods, so that | 
|  | when users return to an application, they don't have to wait for the data to | 
|  | reload. You use the {@link android.app.LoaderManager.LoaderCallbacks} methods | 
|  | when to know when to create a new loader, and to tell the application when it is | 
|  | time to  stop using a loader's data.</p> | 
|  |  | 
|  | <p>{@link android.app.LoaderManager.LoaderCallbacks} includes these | 
|  | methods:</p> | 
|  | <ul> | 
|  | <li>{@link android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()}  — | 
|  | Instantiate and return a new {@link android.content.Loader} for the given ID. | 
|  | </li></ul> | 
|  | <ul> | 
|  | <li> {@link android.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()} | 
|  | — Called when a previously created loader has finished its load. | 
|  | </li></ul> | 
|  | <ul> | 
|  | <li>{@link android.app.LoaderManager.LoaderCallbacks#onLoaderReset onLoaderReset()} | 
|  | — Called when a previously created loader is being reset,  thus  making its | 
|  | data unavailable. | 
|  | </li> | 
|  | </ul> | 
|  | <p>These methods are described in more detail in the following sections.</p> | 
|  |  | 
|  | <h4 id ="onCreateLoader">onCreateLoader</h4> | 
|  |  | 
|  | <p>When you attempt to access a loader (for example, through {@link | 
|  | android.app.LoaderManager#initLoader initLoader()}), it checks to see whether | 
|  | the loader specified by the ID exists. If it doesn't, it triggers the {@link | 
|  | android.app.LoaderManager.LoaderCallbacks} method {@link | 
|  | android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()}. This | 
|  | is where you  create a new loader. Typically this will be a {@link | 
|  | android.content.CursorLoader}, but you can implement your own {@link | 
|  | android.content.Loader} subclass. </p> | 
|  |  | 
|  | <p>In this example, the {@link | 
|  | android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()} | 
|  | callback method creates a {@link android.content.CursorLoader}. You must build | 
|  | the {@link android.content.CursorLoader} using its constructor method, which | 
|  | requires the complete set of information needed to perform a query to the {@link | 
|  | android.content.ContentProvider}. Specifically, it needs:</p> | 
|  | <ul> | 
|  | <li><em>uri</em> — The URI for the content to retrieve. </li> | 
|  | <li><em>projection</em> — A list of which columns to return. Passing | 
|  | <code>null</code> will return all columns, which is inefficient. </li> | 
|  | <li><em>selection</em> — A filter declaring which rows to return, | 
|  | formatted as an SQL WHERE clause (excluding the WHERE itself). Passing | 
|  | <code>null</code> will return all rows for the given URI. </li> | 
|  | <li><em>selectionArgs</em> — You may include ?s in the selection, which will | 
|  | be replaced by the values from <em>selectionArgs</em>, in the order that they appear in | 
|  | the selection. The values will be bound as Strings. </li> | 
|  | <li><em>sortOrder</em> — How to order the rows, formatted as an SQL | 
|  | ORDER BY clause (excluding the ORDER BY itself). Passing <code>null</code> will | 
|  | use the default sort order, which may be unordered.</li> | 
|  | </ul> | 
|  | <p>For example:</p> | 
|  | <pre> | 
|  | // If non-null, this is the current filter the user has provided. | 
|  | String mCurFilter; | 
|  | ... | 
|  | public Loader<Cursor> onCreateLoader(int id, Bundle args) { | 
|  | // This is called when a new Loader needs to be created.  This | 
|  | // sample only has one Loader, so we don't care about the ID. | 
|  | // First, pick the base URI to use depending on whether we are | 
|  | // currently filtering. | 
|  | Uri baseUri; | 
|  | if (mCurFilter != null) { | 
|  | baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, | 
|  | Uri.encode(mCurFilter)); | 
|  | } else { | 
|  | baseUri = Contacts.CONTENT_URI; | 
|  | } | 
|  |  | 
|  | // Now create and return a CursorLoader that will take care of | 
|  | // creating a Cursor for the data being displayed. | 
|  | String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND (" | 
|  | + Contacts.HAS_PHONE_NUMBER + "=1) AND (" | 
|  | + Contacts.DISPLAY_NAME + " != '' ))"; | 
|  | return new CursorLoader(getActivity(), baseUri, | 
|  | CONTACTS_SUMMARY_PROJECTION, select, null, | 
|  | Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC"); | 
|  | }</pre> | 
|  | <h4 id="onLoadFinished">onLoadFinished</h4> | 
|  |  | 
|  | <p>This method is called when a previously created loader has finished its load. | 
|  | This method is guaranteed to be called prior to the release of  the last data | 
|  | that was supplied for this loader.  At this point  you should remove all use of | 
|  | the old data (since it will be released  soon), but should not do your own | 
|  | release of the data since its loader  owns it and will take care of that.</p> | 
|  |  | 
|  |  | 
|  | <p>The loader will release the data once it knows the application  is no longer | 
|  | using it.  For example, if the data is  a cursor from a {@link | 
|  | android.content.CursorLoader},  you should not call {@link | 
|  | android.database.Cursor#close close()} on it yourself. If the cursor is being | 
|  | placed in a {@link android.widget.CursorAdapter}, you should use the {@link | 
|  | android.widget.SimpleCursorAdapter#swapCursor swapCursor()}  method so that the | 
|  | old {@link android.database.Cursor} is not closed. For example:</p> | 
|  |  | 
|  | <pre> | 
|  | // This is the Adapter being used to display the list's data.<br | 
|  | />SimpleCursorAdapter mAdapter; | 
|  | ... | 
|  |  | 
|  | public void onLoadFinished(Loader<Cursor> loader, Cursor data) { | 
|  | // Swap the new cursor in.  (The framework will take care of closing the | 
|  | // old cursor once we return.) | 
|  | mAdapter.swapCursor(data); | 
|  | }</pre> | 
|  |  | 
|  | <h4 id="onLoaderReset">onLoaderReset</h4> | 
|  |  | 
|  | <p>This method is called when a previously created loader is being reset,  thus | 
|  | making its data unavailable. This callback lets you find  out when the data is | 
|  | about to be released so you can remove your  reference to it.  </p> | 
|  | <p>This implementation calls | 
|  | {@link android.widget.SimpleCursorAdapter#swapCursor swapCursor()} | 
|  | with a value of <code>null</code>:</p> | 
|  |  | 
|  | <pre> | 
|  | // This is the Adapter being used to display the list's data. | 
|  | SimpleCursorAdapter mAdapter; | 
|  | ... | 
|  |  | 
|  | public void onLoaderReset(Loader<Cursor> loader) { | 
|  | // This is called when the last Cursor provided to onLoadFinished() | 
|  | // above is about to be closed.  We need to make sure we are no | 
|  | // longer using it. | 
|  | mAdapter.swapCursor(null); | 
|  | }</pre> | 
|  |  | 
|  |  | 
|  | <h2 id="example">Example</h2> | 
|  |  | 
|  | <p>As an example, here is the full implementation of a {@link | 
|  | android.app.Fragment} that displays a {@link android.widget.ListView} containing | 
|  | the results of a query against the contacts content provider. It uses a {@link | 
|  | android.content.CursorLoader} to manage the query on the provider.</p> | 
|  |  | 
|  | <p>For an application to access a user's contacts, as shown in this example, its | 
|  | manifest must include the permission | 
|  | {@link android.Manifest.permission#READ_CONTACTS READ_CONTACTS}.</p> | 
|  |  | 
|  | <pre> | 
|  | public static class CursorLoaderListFragment extends ListFragment | 
|  | implements OnQueryTextListener, LoaderManager.LoaderCallbacks<Cursor> { | 
|  |  | 
|  | // This is the Adapter being used to display the list's data. | 
|  | SimpleCursorAdapter mAdapter; | 
|  |  | 
|  | // If non-null, this is the current filter the user has provided. | 
|  | String mCurFilter; | 
|  |  | 
|  | @Override public void onActivityCreated(Bundle savedInstanceState) { | 
|  | super.onActivityCreated(savedInstanceState); | 
|  |  | 
|  | // Give some text to display if there is no data.  In a real | 
|  | // application this would come from a resource. | 
|  | setEmptyText("No phone numbers"); | 
|  |  | 
|  | // We have a menu item to show in action bar. | 
|  | setHasOptionsMenu(true); | 
|  |  | 
|  | // Create an empty adapter we will use to display the loaded data. | 
|  | mAdapter = new SimpleCursorAdapter(getActivity(), | 
|  | android.R.layout.simple_list_item_2, null, | 
|  | new String[] { Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS }, | 
|  | new int[] { android.R.id.text1, android.R.id.text2 }, 0); | 
|  | setListAdapter(mAdapter); | 
|  |  | 
|  | // Prepare the loader.  Either re-connect with an existing one, | 
|  | // or start a new one. | 
|  | getLoaderManager().initLoader(0, null, this); | 
|  | } | 
|  |  | 
|  | @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { | 
|  | // Place an action bar item for searching. | 
|  | MenuItem item = menu.add("Search"); | 
|  | item.setIcon(android.R.drawable.ic_menu_search); | 
|  | item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); | 
|  | SearchView sv = new SearchView(getActivity()); | 
|  | sv.setOnQueryTextListener(this); | 
|  | item.setActionView(sv); | 
|  | } | 
|  |  | 
|  | public boolean onQueryTextChange(String newText) { | 
|  | // Called when the action bar search text has changed.  Update | 
|  | // the search filter, and restart the loader to do a new query | 
|  | // with this filter. | 
|  | mCurFilter = !TextUtils.isEmpty(newText) ? newText : null; | 
|  | getLoaderManager().restartLoader(0, null, this); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | @Override public boolean onQueryTextSubmit(String query) { | 
|  | // Don't care about this. | 
|  | return true; | 
|  | } | 
|  |  | 
|  | @Override public void onListItemClick(ListView l, View v, int position, long id) { | 
|  | // Insert desired behavior here. | 
|  | Log.i("FragmentComplexList", "Item clicked: " + id); | 
|  | } | 
|  |  | 
|  | // These are the Contacts rows that we will retrieve. | 
|  | static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] { | 
|  | Contacts._ID, | 
|  | Contacts.DISPLAY_NAME, | 
|  | Contacts.CONTACT_STATUS, | 
|  | Contacts.CONTACT_PRESENCE, | 
|  | Contacts.PHOTO_ID, | 
|  | Contacts.LOOKUP_KEY, | 
|  | }; | 
|  | public Loader<Cursor> onCreateLoader(int id, Bundle args) { | 
|  | // This is called when a new Loader needs to be created.  This | 
|  | // sample only has one Loader, so we don't care about the ID. | 
|  | // First, pick the base URI to use depending on whether we are | 
|  | // currently filtering. | 
|  | Uri baseUri; | 
|  | if (mCurFilter != null) { | 
|  | baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, | 
|  | Uri.encode(mCurFilter)); | 
|  | } else { | 
|  | baseUri = Contacts.CONTENT_URI; | 
|  | } | 
|  |  | 
|  | // Now create and return a CursorLoader that will take care of | 
|  | // creating a Cursor for the data being displayed. | 
|  | String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND (" | 
|  | + Contacts.HAS_PHONE_NUMBER + "=1) AND (" | 
|  | + Contacts.DISPLAY_NAME + " != '' ))"; | 
|  | return new CursorLoader(getActivity(), baseUri, | 
|  | CONTACTS_SUMMARY_PROJECTION, select, null, | 
|  | Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC"); | 
|  | } | 
|  |  | 
|  | public void onLoadFinished(Loader<Cursor> loader, Cursor data) { | 
|  | // Swap the new cursor in.  (The framework will take care of closing the | 
|  | // old cursor once we return.) | 
|  | mAdapter.swapCursor(data); | 
|  | } | 
|  |  | 
|  | public void onLoaderReset(Loader<Cursor> loader) { | 
|  | // This is called when the last Cursor provided to onLoadFinished() | 
|  | // above is about to be closed.  We need to make sure we are no | 
|  | // longer using it. | 
|  | mAdapter.swapCursor(null); | 
|  | } | 
|  | }</pre> | 
|  | <h3 id="more_examples">More Examples</h3> | 
|  |  | 
|  | <p>There are a few different samples in <strong>ApiDemos</strong> that | 
|  | illustrate how to use loaders:</p> | 
|  | <ul> | 
|  | <li><a | 
|  | href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderCursor.html"> | 
|  | LoaderCursor</a> — A complete version of the | 
|  | snippet shown above.</li> | 
|  | <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderThrottle.html"> LoaderThrottle</a> — An example of how to use throttling to | 
|  | reduce the number of queries a content provider does when its data changes.</li> | 
|  | </ul> | 
|  |  | 
|  | <p>For information on downloading and installing the SDK samples, see <a | 
|  | href="http://developer.android.com/resources/samples/get.html"> Getting the | 
|  | Samples</a>. </p> | 
|  |  |