1page.title=Loaders 2parent.title=Activities 3parent.link=activities.html 4@jd:body 5<div id="qv-wrapper"> 6<div id="qv"> 7 <h2>In this document</h2> 8 <ol> 9 <li><a href="#summary">Loader API Summary</a></li> 10 <li><a href="#app">Using Loaders in an Application</a> 11 <ol> 12 <li><a href="#requirements"></a></li> 13 <li><a href="#starting">Starting a Loader</a></li> 14 <li><a href="#restarting">Restarting a Loader</a></li> 15 <li><a href="#callback">Using the LoaderManager Callbacks</a></li> 16 </ol> 17 </li> 18 <li><a href="#example">Example</a> 19 <ol> 20 <li><a href="#more_examples">More Examples</a></li> 21 </ol> 22 </li> 23 </ol> 24 25 <h2>Key classes</h2> 26 <ol> 27 <li>{@link android.app.LoaderManager}</li> 28 <li>{@link android.content.Loader}</li> 29 30 </ol> 31 32 <h2>Related samples</h2> 33 <ol> 34 <li> <a 35href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderCursor.html"> 36LoaderCursor</a></li> 37 <li> <a 38href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderThrottle.html"> 39LoaderThrottle</a></li> 40 </ol> 41 </div> 42</div> 43 44<p>Introduced in Android 3.0, loaders make it easy to asynchronously load data 45in an activity or fragment. Loaders have these characteristics:</p> 46 <ul> 47 <li>They are available to every {@link android.app.Activity} and {@link 48android.app.Fragment}.</li> 49 <li>They provide asynchronous loading of data.</li> 50 <li>They monitor the source of their data and deliver new results when the 51content changes.</li> 52 <li>They automatically reconnect to the last loader's cursor when being 53recreated after a configuration change. Thus, they don't need to re-query their 54data.</li> 55 </ul> 56 57<h2 id="summary">Loader API Summary</h2> 58 59<p>There are multiple classes and interfaces that may be involved in using 60loaders in an application. They are summarized in this table:</p> 61 62<table> 63 <tr> 64 <th>Class/Interface</th> 65 <th>Description</th> 66 </tr> 67 <tr> 68 <td>{@link android.app.LoaderManager}</td> 69 <td>An abstract class associated with an {@link android.app.Activity} or 70{@link android.app.Fragment} for managing one or more {@link 71android.content.Loader} instances. This helps an application manage 72longer-running operations in conjunction with the {@link android.app.Activity} 73or {@link android.app.Fragment} lifecycle; the most common use of this is with a 74{@link android.content.CursorLoader}, however applications are free to write 75their own loaders for loading other types of data. 76 <br /> 77 <br /> 78 There is only one {@link android.app.LoaderManager} per activity or fragment. But a {@link android.app.LoaderManager} can have 79multiple loaders.</td> 80 </tr> 81 <tr> 82 <td>{@link android.app.LoaderManager.LoaderCallbacks}</td> 83 <td>A callback interface for a client to interact with the {@link 84android.app.LoaderManager}. For example, you use the {@link 85android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()} 86callback method to create a new loader.</td> 87 </tr> 88 <tr> 89 <td>{@link android.content.Loader}</td> 90 <td>An abstract class that performs asynchronous loading of data. This is 91the base class for a loader. You would typically use {@link 92android.content.CursorLoader}, but you can implement your own subclass. While 93loaders are active they should monitor the source of their data and deliver new 94results when the contents change. </td> 95 </tr> 96 <tr> 97 <td>{@link android.content.AsyncTaskLoader}</td> 98 <td>Abstract loader that provides an {@link android.os.AsyncTask} to do the work.</td> 99 </tr> 100 <tr> 101 <td>{@link android.content.CursorLoader}</td> 102 <td>A subclass of {@link android.content.AsyncTaskLoader} that queries the 103{@link android.content.ContentResolver} and returns a {@link 104android.database.Cursor}. This class implements the {@link 105android.content.Loader} protocol in a standard way for querying cursors, 106building on {@link android.content.AsyncTaskLoader} to perform the cursor query 107on a background thread so that it does not block the application's UI. Using 108this loader is the best way to asynchronously load data from a {@link 109android.content.ContentProvider}, instead of performing a managed query through 110the fragment or activity's APIs.</td> 111 </tr> 112</table> 113 114<p>The classes and interfaces in the above table are the essential components 115you'll use to implement a loader in your application. You won't need all of them 116for each loader you create, but you'll always need a reference to the {@link 117android.app.LoaderManager} in order to initialize a loader and an implementation 118of a {@link android.content.Loader} class such as {@link 119android.content.CursorLoader}. The following sections show you how to use these 120classes and interfaces in an application.</p> 121 122<h2 id ="app">Using Loaders in an Application</h2> 123<p>This section describes how to use loaders in an Android application. An 124application that uses loaders typically includes the following:</p> 125<ul> 126 <li>An {@link android.app.Activity} or {@link android.app.Fragment}.</li> 127 <li>An instance of the {@link android.app.LoaderManager}.</li> 128 <li>A {@link android.content.CursorLoader} to load data backed by a {@link 129android.content.ContentProvider}. Alternatively, you can implement your own subclass 130of {@link android.content.Loader} or {@link android.content.AsyncTaskLoader} to 131load data from some other source.</li> 132 <li>An implementation for {@link android.app.LoaderManager.LoaderCallbacks}. 133This is where you create new loaders and manage your references to existing 134loaders.</li> 135<li>A way of displaying the loader's data, such as a {@link 136android.widget.SimpleCursorAdapter}.</li> 137 <li>A data source, such as a {@link android.content.ContentProvider}, when using a 138{@link android.content.CursorLoader}.</li> 139</ul> 140<h3 id="starting">Starting a Loader</h3> 141 142<p>The {@link android.app.LoaderManager} manages one or more {@link 143android.content.Loader} instances within an {@link android.app.Activity} or 144{@link android.app.Fragment}. There is only one {@link 145android.app.LoaderManager} per activity or fragment.</p> 146 147<p>You typically 148initialize a {@link android.content.Loader} within the activity's {@link 149android.app.Activity#onCreate onCreate()} method, or within the fragment's 150{@link android.app.Fragment#onActivityCreated onActivityCreated()} method. You 151do this as follows:</p> 152 153<pre>// Prepare the loader. Either re-connect with an existing one, 154// or start a new one. 155getLoaderManager().initLoader(0, null, this);</pre> 156 157<p>The {@link android.app.LoaderManager#initLoader initLoader()} method takes 158the following parameters:</p> 159<ul> 160 <li>A unique ID that identifies the loader. In this example, the ID is 0.</li> 161<li>Optional arguments to supply to the loader at 162construction (<code>null</code> in this example).</li> 163 164<li>A {@link android.app.LoaderManager.LoaderCallbacks} implementation, which 165the {@link android.app.LoaderManager} calls to report loader events. In this 166example, the local class implements the {@link 167android.app.LoaderManager.LoaderCallbacks} interface, so it passes a reference 168to itself, {@code this}.</li> 169</ul> 170<p>The {@link android.app.LoaderManager#initLoader initLoader()} call ensures that a loader 171is initialized and active. It has two possible outcomes:</p> 172<ul> 173 <li>If the loader specified by the ID already exists, the last created loader 174is reused.</li> 175 <li>If the loader specified by the ID does <em>not</em> exist, 176{@link android.app.LoaderManager#initLoader initLoader()} triggers the 177{@link android.app.LoaderManager.LoaderCallbacks} method {@link android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()}. 178This is where you implement the code to instantiate and return a new loader. 179For more discussion, see the section <a 180href="#onCreateLoader">onCreateLoader</a>.</li> 181</ul> 182<p>In either case, the given {@link android.app.LoaderManager.LoaderCallbacks} 183implementation is associated with the loader, and will be called when the 184loader state changes. If at the point of this call the caller is in its 185started state, and the requested loader already exists and has generated its 186data, then the system calls {@link 187android.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()} 188immediately (during {@link android.app.LoaderManager#initLoader initLoader()}), 189so you must be prepared for this to happen. See <a href="#onLoadFinished"> 190onLoadFinished</a> for more discussion of this callback</p> 191 192<p>Note that the {@link android.app.LoaderManager#initLoader initLoader()} 193method returns the {@link android.content.Loader} that is created, but you don't 194need to capture a reference to it. The {@link android.app.LoaderManager} manages 195the life of the loader automatically. The {@link android.app.LoaderManager} 196starts and stops loading when necessary, and maintains the state of the loader 197and its associated content. As this implies, you rarely interact with loaders 198directly (though for an example of using loader methods to fine-tune a loader's 199behavior, see the <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderThrottle.html"> LoaderThrottle</a> sample). 200You most commonly use the {@link 201android.app.LoaderManager.LoaderCallbacks} methods to intervene in the loading 202process when particular events occur. For more discussion of this topic, see <a 203href="#callback">Using the LoaderManager Callbacks</a>.</p> 204 205<h3 id="restarting">Restarting a Loader</h3> 206 207<p>When you use {@link android.app.LoaderManager#initLoader initLoader()}, as 208shown above, it uses an existing loader with the specified ID if there is one. 209If there isn't, it creates one. But sometimes you want to discard your old data 210and start over.</p> 211 212<p>To discard your old data, you use {@link 213android.app.LoaderManager#restartLoader restartLoader()}. For example, this 214implementation of {@link android.widget.SearchView.OnQueryTextListener} restarts 215the loader when the user's query changes. The loader needs to be restarted so 216that it can use the revised search filter to do a new query:</p> 217 218<pre> 219public boolean onQueryTextChanged(String newText) { 220 // Called when the action bar search text has changed. Update 221 // the search filter, and restart the loader to do a new query 222 // with this filter. 223 mCurFilter = !TextUtils.isEmpty(newText) ? newText : null; 224 getLoaderManager().restartLoader(0, null, this); 225 return true; 226}</pre> 227 228<h3 id="callback">Using the LoaderManager Callbacks</h3> 229 230<p>{@link android.app.LoaderManager.LoaderCallbacks} is a callback interface 231that lets a client interact with the {@link android.app.LoaderManager}. </p> 232<p>Loaders, in particular {@link android.content.CursorLoader}, are expected to 233retain their data after being stopped. This allows applications to keep their 234data across the activity or fragment's {@link android.app.Activity#onStop 235onStop()} and {@link android.app.Activity#onStart onStart()} methods, so that 236when users return to an application, they don't have to wait for the data to 237reload. You use the {@link android.app.LoaderManager.LoaderCallbacks} methods 238when to know when to create a new loader, and to tell the application when it is 239 time to stop using a loader's data.</p> 240 241<p>{@link android.app.LoaderManager.LoaderCallbacks} includes these 242methods:</p> 243<ul> 244 <li>{@link android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()} — 245Instantiate and return a new {@link android.content.Loader} for the given ID. 246</li></ul> 247<ul> 248 <li> {@link android.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()} 249— Called when a previously created loader has finished its load. 250</li></ul> 251<ul> 252 <li>{@link android.app.LoaderManager.LoaderCallbacks#onLoaderReset onLoaderReset()} 253 — Called when a previously created loader is being reset, thus making its 254data unavailable. 255</li> 256</ul> 257<p>These methods are described in more detail in the following sections.</p> 258 259<h4 id ="onCreateLoader">onCreateLoader</h4> 260 261<p>When you attempt to access a loader (for example, through {@link 262android.app.LoaderManager#initLoader initLoader()}), it checks to see whether 263the loader specified by the ID exists. If it doesn't, it triggers the {@link 264android.app.LoaderManager.LoaderCallbacks} method {@link 265android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()}. This 266is where you create a new loader. Typically this will be a {@link 267android.content.CursorLoader}, but you can implement your own {@link 268android.content.Loader} subclass. </p> 269 270<p>In this example, the {@link 271android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()} 272callback method creates a {@link android.content.CursorLoader}. You must build 273the {@link android.content.CursorLoader} using its constructor method, which 274requires the complete set of information needed to perform a query to the {@link 275android.content.ContentProvider}. Specifically, it needs:</p> 276<ul> 277 <li><em>uri</em> — The URI for the content to retrieve. </li> 278 <li><em>projection</em> — A list of which columns to return. Passing 279<code>null</code> will return all columns, which is inefficient. </li> 280 <li><em>selection</em> — A filter declaring which rows to return, 281formatted as an SQL WHERE clause (excluding the WHERE itself). Passing 282<code>null</code> will return all rows for the given URI. </li> 283 <li><em>selectionArgs</em> — You may include ?s in the selection, which will 284be replaced by the values from <em>selectionArgs</em>, in the order that they appear in 285the selection. The values will be bound as Strings. </li> 286 <li><em>sortOrder</em> — How to order the rows, formatted as an SQL 287ORDER BY clause (excluding the ORDER BY itself). Passing <code>null</code> will 288use the default sort order, which may be unordered.</li> 289</ul> 290<p>For example:</p> 291<pre> 292 // If non-null, this is the current filter the user has provided. 293String mCurFilter; 294... 295public Loader<Cursor> onCreateLoader(int id, Bundle args) { 296 // This is called when a new Loader needs to be created. This 297 // sample only has one Loader, so we don't care about the ID. 298 // First, pick the base URI to use depending on whether we are 299 // currently filtering. 300 Uri baseUri; 301 if (mCurFilter != null) { 302 baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, 303 Uri.encode(mCurFilter)); 304 } else { 305 baseUri = Contacts.CONTENT_URI; 306 } 307 308 // Now create and return a CursorLoader that will take care of 309 // creating a Cursor for the data being displayed. 310 String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND (" 311 + Contacts.HAS_PHONE_NUMBER + "=1) AND (" 312 + Contacts.DISPLAY_NAME + " != '' ))"; 313 return new CursorLoader(getActivity(), baseUri, 314 CONTACTS_SUMMARY_PROJECTION, select, null, 315 Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC"); 316}</pre> 317<h4 id="onLoadFinished">onLoadFinished</h4> 318 319<p>This method is called when a previously created loader has finished its load. 320This method is guaranteed to be called prior to the release of the last data 321that was supplied for this loader. At this point you should remove all use of 322the old data (since it will be released soon), but should not do your own 323release of the data since its loader owns it and will take care of that.</p> 324 325 326<p>The loader will release the data once it knows the application is no longer 327using it. For example, if the data is a cursor from a {@link 328android.content.CursorLoader}, you should not call {@link 329android.database.Cursor#close close()} on it yourself. If the cursor is being 330placed in a {@link android.widget.CursorAdapter}, you should use the {@link 331android.widget.SimpleCursorAdapter#swapCursor swapCursor()} method so that the 332old {@link android.database.Cursor} is not closed. For example:</p> 333 334<pre> 335// This is the Adapter being used to display the list's data.<br 336/>SimpleCursorAdapter mAdapter; 337... 338 339public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 340 // Swap the new cursor in. (The framework will take care of closing the 341 // old cursor once we return.) 342 mAdapter.swapCursor(data); 343}</pre> 344 345<h4 id="onLoaderReset">onLoaderReset</h4> 346 347<p>This method is called when a previously created loader is being reset, thus 348making its data unavailable. This callback lets you find out when the data is 349about to be released so you can remove your reference to it. </p> 350<p>This implementation calls 351{@link android.widget.SimpleCursorAdapter#swapCursor swapCursor()} 352with a value of <code>null</code>:</p> 353 354<pre> 355// This is the Adapter being used to display the list's data. 356SimpleCursorAdapter mAdapter; 357... 358 359public void onLoaderReset(Loader<Cursor> loader) { 360 // This is called when the last Cursor provided to onLoadFinished() 361 // above is about to be closed. We need to make sure we are no 362 // longer using it. 363 mAdapter.swapCursor(null); 364}</pre> 365 366 367<h2 id="example">Example</h2> 368 369<p>As an example, here is the full implementation of a {@link 370android.app.Fragment} that displays a {@link android.widget.ListView} containing 371the results of a query against the contacts content provider. It uses a {@link 372android.content.CursorLoader} to manage the query on the provider.</p> 373 374<p>For an application to access a user's contacts, as shown in this example, its 375manifest must include the permission 376{@link android.Manifest.permission#READ_CONTACTS READ_CONTACTS}.</p> 377 378<pre> 379public static class CursorLoaderListFragment extends ListFragment 380 implements OnQueryTextListener, LoaderManager.LoaderCallbacks<Cursor> { 381 382 // This is the Adapter being used to display the list's data. 383 SimpleCursorAdapter mAdapter; 384 385 // If non-null, this is the current filter the user has provided. 386 String mCurFilter; 387 388 @Override public void onActivityCreated(Bundle savedInstanceState) { 389 super.onActivityCreated(savedInstanceState); 390 391 // Give some text to display if there is no data. In a real 392 // application this would come from a resource. 393 setEmptyText("No phone numbers"); 394 395 // We have a menu item to show in action bar. 396 setHasOptionsMenu(true); 397 398 // Create an empty adapter we will use to display the loaded data. 399 mAdapter = new SimpleCursorAdapter(getActivity(), 400 android.R.layout.simple_list_item_2, null, 401 new String[] { Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS }, 402 new int[] { android.R.id.text1, android.R.id.text2 }, 0); 403 setListAdapter(mAdapter); 404 405 // Prepare the loader. Either re-connect with an existing one, 406 // or start a new one. 407 getLoaderManager().initLoader(0, null, this); 408 } 409 410 @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 411 // Place an action bar item for searching. 412 MenuItem item = menu.add("Search"); 413 item.setIcon(android.R.drawable.ic_menu_search); 414 item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); 415 SearchView sv = new SearchView(getActivity()); 416 sv.setOnQueryTextListener(this); 417 item.setActionView(sv); 418 } 419 420 public boolean onQueryTextChange(String newText) { 421 // Called when the action bar search text has changed. Update 422 // the search filter, and restart the loader to do a new query 423 // with this filter. 424 mCurFilter = !TextUtils.isEmpty(newText) ? newText : null; 425 getLoaderManager().restartLoader(0, null, this); 426 return true; 427 } 428 429 @Override public boolean onQueryTextSubmit(String query) { 430 // Don't care about this. 431 return true; 432 } 433 434 @Override public void onListItemClick(ListView l, View v, int position, long id) { 435 // Insert desired behavior here. 436 Log.i("FragmentComplexList", "Item clicked: " + id); 437 } 438 439 // These are the Contacts rows that we will retrieve. 440 static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] { 441 Contacts._ID, 442 Contacts.DISPLAY_NAME, 443 Contacts.CONTACT_STATUS, 444 Contacts.CONTACT_PRESENCE, 445 Contacts.PHOTO_ID, 446 Contacts.LOOKUP_KEY, 447 }; 448 public Loader<Cursor> onCreateLoader(int id, Bundle args) { 449 // This is called when a new Loader needs to be created. This 450 // sample only has one Loader, so we don't care about the ID. 451 // First, pick the base URI to use depending on whether we are 452 // currently filtering. 453 Uri baseUri; 454 if (mCurFilter != null) { 455 baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, 456 Uri.encode(mCurFilter)); 457 } else { 458 baseUri = Contacts.CONTENT_URI; 459 } 460 461 // Now create and return a CursorLoader that will take care of 462 // creating a Cursor for the data being displayed. 463 String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND (" 464 + Contacts.HAS_PHONE_NUMBER + "=1) AND (" 465 + Contacts.DISPLAY_NAME + " != '' ))"; 466 return new CursorLoader(getActivity(), baseUri, 467 CONTACTS_SUMMARY_PROJECTION, select, null, 468 Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC"); 469 } 470 471 public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 472 // Swap the new cursor in. (The framework will take care of closing the 473 // old cursor once we return.) 474 mAdapter.swapCursor(data); 475 } 476 477 public void onLoaderReset(Loader<Cursor> loader) { 478 // This is called when the last Cursor provided to onLoadFinished() 479 // above is about to be closed. We need to make sure we are no 480 // longer using it. 481 mAdapter.swapCursor(null); 482 } 483}</pre> 484<h3 id="more_examples">More Examples</h3> 485 486<p>There are a few different samples in <strong>ApiDemos</strong> that 487illustrate how to use loaders:</p> 488<ul> 489 <li><a 490href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderCursor.html"> 491LoaderCursor</a> — A complete version of the 492snippet shown above.</li> 493 <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 494reduce the number of queries a content provider does then its data changes.</li> 495</ul> 496 497<p>For information on downloading and installing the SDK samples, see <a 498href="http://developer.android.com/resources/samples/get.html"> Getting the 499Samples</a>. </p> 500 501