| Scott Main | a564745 | 2011-02-15 17:25:26 -0800 | [diff] [blame] | 1 | page.title=Loaders |
| 2 | parent.title=Activities |
| 3 | parent.link=activities.html |
| Katie McCormick | d178211 | 2011-02-04 15:31:29 -0800 | [diff] [blame] | 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> |
| Scott Main | 13033ea | 2011-02-15 13:18:30 -0800 | [diff] [blame] | 34 | <li> <a |
| Scott Main | 19aad29 | 2011-10-18 16:57:32 -0700 | [diff] [blame] | 35 | href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderCursor.html"> |
| 36 | LoaderCursor</a></li> |
| Scott Main | 13033ea | 2011-02-15 13:18:30 -0800 | [diff] [blame] | 37 | <li> <a |
| 38 | href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderThrottle.html"> |
| 39 | LoaderThrottle</a></li> |
| Katie McCormick | d178211 | 2011-02-04 15:31:29 -0800 | [diff] [blame] | 40 | </ol> |
| 41 | </div> |
| 42 | </div> |
| 43 | |
| 44 | <p>Introduced in Android 3.0, loaders make it easy to asynchronously load data |
| 45 | in an activity or fragment. Loaders have these characteristics:</p> |
| 46 | <ul> |
| 47 | <li>They are available to every {@link android.app.Activity} and {@link |
| 48 | android.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 |
| 51 | content changes.</li> |
| 52 | <li>They automatically reconnect to the last loader's cursor when being |
| 53 | recreated after a configuration change. Thus, they don't need to re-query their |
| 54 | data.</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 |
| 60 | loaders 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 |
| 71 | android.content.Loader} instances. This helps an application manage |
| 72 | longer-running operations in conjunction with the {@link android.app.Activity} |
| 73 | or {@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 |
| 75 | their 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 |
| 79 | multiple 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 |
| 84 | android.app.LoaderManager}. For example, you use the {@link |
| 85 | android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()} |
| 86 | callback 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 |
| 91 | the base class for a loader. You would typically use {@link |
| 92 | android.content.CursorLoader}, but you can implement your own subclass. While |
| 93 | loaders are active they should monitor the source of their data and deliver new |
| 94 | results 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 |
| 104 | android.database.Cursor}. This class implements the {@link |
| 105 | android.content.Loader} protocol in a standard way for querying cursors, |
| 106 | building on {@link android.content.AsyncTaskLoader} to perform the cursor query |
| 107 | on a background thread so that it does not block the application's UI. Using |
| 108 | this loader is the best way to asynchronously load data from a {@link |
| 109 | android.content.ContentProvider}, instead of performing a managed query through |
| 110 | the 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 |
| 115 | you'll use to implement a loader in your application. You won't need all of them |
| 116 | for each loader you create, but you'll always need a reference to the {@link |
| 117 | android.app.LoaderManager} in order to initialize a loader and an implementation |
| 118 | of a {@link android.content.Loader} class such as {@link |
| 119 | android.content.CursorLoader}. The following sections show you how to use these |
| 120 | classes 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 |
| 124 | application 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 |
| 129 | android.content.ContentProvider}. Alternatively, you can implement your own subclass |
| 130 | of {@link android.content.Loader} or {@link android.content.AsyncTaskLoader} to |
| 131 | load data from some other source.</li> |
| 132 | <li>An implementation for {@link android.app.LoaderManager.LoaderCallbacks}. |
| 133 | This is where you create new loaders and manage your references to existing |
| 134 | loaders.</li> |
| 135 | <li>A way of displaying the loader's data, such as a {@link |
| 136 | android.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 |
| 143 | android.content.Loader} instances within an {@link android.app.Activity} or |
| 144 | {@link android.app.Fragment}. There is only one {@link |
| 145 | android.app.LoaderManager} per activity or fragment.</p> |
| 146 | |
| 147 | <p>You typically |
| 148 | initialize a {@link android.content.Loader} within the activity's {@link |
| 149 | android.app.Activity#onCreate onCreate()} method, or within the fragment's |
| 150 | {@link android.app.Fragment#onActivityCreated onActivityCreated()} method. You |
| 151 | do this as follows:</p> |
| 152 | |
| 153 | <pre>// Prepare the loader. Either re-connect with an existing one, |
| 154 | // or start a new one. |
| 155 | getLoaderManager().initLoader(0, null, this);</pre> |
| 156 | |
| 157 | <p>The {@link android.app.LoaderManager#initLoader initLoader()} method takes |
| 158 | the 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 |
| 162 | construction (<code>null</code> in this example).</li> |
| 163 | |
| 164 | <li>A {@link android.app.LoaderManager.LoaderCallbacks} implementation, which |
| 165 | the {@link android.app.LoaderManager} calls to report loader events. In this |
| 166 | example, the local class implements the {@link |
| 167 | android.app.LoaderManager.LoaderCallbacks} interface, so it passes a reference |
| 168 | to itself, {@code this}.</li> |
| 169 | </ul> |
| 170 | <p>The {@link android.app.LoaderManager#initLoader initLoader()} call ensures that a loader |
| 171 | is 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 |
| 174 | is 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()}. |
| 178 | This is where you implement the code to instantiate and return a new loader. |
| 179 | For more discussion, see the section <a |
| 180 | href="#onCreateLoader">onCreateLoader</a>.</li> |
| 181 | </ul> |
| 182 | <p>In either case, the given {@link android.app.LoaderManager.LoaderCallbacks} |
| 183 | implementation is associated with the loader, and will be called when the |
| 184 | loader state changes. If at the point of this call the caller is in its |
| 185 | started state, and the requested loader already exists and has generated its |
| 186 | data, then the system calls {@link |
| 187 | android.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()} |
| 188 | immediately (during {@link android.app.LoaderManager#initLoader initLoader()}), |
| 189 | so you must be prepared for this to happen. See <a href="#onLoadFinished"> |
| 190 | onLoadFinished</a> for more discussion of this callback</p> |
| 191 | |
| 192 | <p>Note that the {@link android.app.LoaderManager#initLoader initLoader()} |
| 193 | method returns the {@link android.content.Loader} that is created, but you don't |
| 194 | need to capture a reference to it. The {@link android.app.LoaderManager} manages |
| 195 | the life of the loader automatically. The {@link android.app.LoaderManager} |
| 196 | starts and stops loading when necessary, and maintains the state of the loader |
| 197 | and its associated content. As this implies, you rarely interact with loaders |
| 198 | directly (though for an example of using loader methods to fine-tune a loader's |
| 199 | behavior, see the <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderThrottle.html"> LoaderThrottle</a> sample). |
| 200 | You most commonly use the {@link |
| 201 | android.app.LoaderManager.LoaderCallbacks} methods to intervene in the loading |
| 202 | process when particular events occur. For more discussion of this topic, see <a |
| 203 | href="#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 |
| 208 | shown above, it uses an existing loader with the specified ID if there is one. |
| 209 | If there isn't, it creates one. But sometimes you want to discard your old data |
| 210 | and start over.</p> |
| 211 | |
| 212 | <p>To discard your old data, you use {@link |
| 213 | android.app.LoaderManager#restartLoader restartLoader()}. For example, this |
| 214 | implementation of {@link android.widget.SearchView.OnQueryTextListener} restarts |
| 215 | the loader when the user's query changes. The loader needs to be restarted so |
| 216 | that it can use the revised search filter to do a new query:</p> |
| 217 | |
| 218 | <pre> |
| 219 | public 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 |
| 231 | that lets a client interact with the {@link android.app.LoaderManager}. </p> |
| 232 | <p>Loaders, in particular {@link android.content.CursorLoader}, are expected to |
| 233 | retain their data after being stopped. This allows applications to keep their |
| 234 | data across the activity or fragment's {@link android.app.Activity#onStop |
| 235 | onStop()} and {@link android.app.Activity#onStart onStart()} methods, so that |
| 236 | when users return to an application, they don't have to wait for the data to |
| 237 | reload. You use the {@link android.app.LoaderManager.LoaderCallbacks} methods |
| 238 | when 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 |
| 242 | methods:</p> |
| 243 | <ul> |
| 244 | <li>{@link android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()} — |
| 245 | Instantiate 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 |
| 254 | data 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 |
| 262 | android.app.LoaderManager#initLoader initLoader()}), it checks to see whether |
| 263 | the loader specified by the ID exists. If it doesn't, it triggers the {@link |
| 264 | android.app.LoaderManager.LoaderCallbacks} method {@link |
| 265 | android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()}. This |
| 266 | is where you create a new loader. Typically this will be a {@link |
| 267 | android.content.CursorLoader}, but you can implement your own {@link |
| 268 | android.content.Loader} subclass. </p> |
| 269 | |
| 270 | <p>In this example, the {@link |
| 271 | android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()} |
| 272 | callback method creates a {@link android.content.CursorLoader}. You must build |
| 273 | the {@link android.content.CursorLoader} using its constructor method, which |
| 274 | requires the complete set of information needed to perform a query to the {@link |
| 275 | android.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, |
| 281 | formatted 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 |
| 284 | be replaced by the values from <em>selectionArgs</em>, in the order that they appear in |
| 285 | the selection. The values will be bound as Strings. </li> |
| 286 | <li><em>sortOrder</em> — How to order the rows, formatted as an SQL |
| 287 | ORDER BY clause (excluding the ORDER BY itself). Passing <code>null</code> will |
| 288 | use 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. |
| 293 | String mCurFilter; |
| 294 | ... |
| 295 | public 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. |
| 320 | This method is guaranteed to be called prior to the release of the last data |
| 321 | that was supplied for this loader. At this point you should remove all use of |
| 322 | the old data (since it will be released soon), but should not do your own |
| 323 | release 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 |
| 327 | using it. For example, if the data is a cursor from a {@link |
| 328 | android.content.CursorLoader}, you should not call {@link |
| 329 | android.database.Cursor#close close()} on it yourself. If the cursor is being |
| 330 | placed in a {@link android.widget.CursorAdapter}, you should use the {@link |
| 331 | android.widget.SimpleCursorAdapter#swapCursor swapCursor()} method so that the |
| 332 | old {@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 | |
| 339 | public 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 |
| 348 | making its data unavailable. This callback lets you find out when the data is |
| 349 | about to be released so you can remove your reference to it. </p> |
| 350 | <p>This implementation calls |
| 351 | {@link android.widget.SimpleCursorAdapter#swapCursor swapCursor()} |
| 352 | with a value of <code>null</code>:</p> |
| 353 | |
| 354 | <pre> |
| 355 | // This is the Adapter being used to display the list's data. |
| 356 | SimpleCursorAdapter mAdapter; |
| 357 | ... |
| 358 | |
| 359 | public 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 |
| 370 | android.app.Fragment} that displays a {@link android.widget.ListView} containing |
| 371 | the results of a query against the contacts content provider. It uses a {@link |
| 372 | android.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 |
| 375 | manifest must include the permission |
| 376 | {@link android.Manifest.permission#READ_CONTACTS READ_CONTACTS}.</p> |
| 377 | |
| 378 | <pre> |
| 379 | public 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 |
| 487 | illustrate how to use loaders:</p> |
| 488 | <ul> |
| Scott Main | 19aad29 | 2011-10-18 16:57:32 -0700 | [diff] [blame] | 489 | <li><a |
| 490 | href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderCursor.html"> |
| 491 | LoaderCursor</a> — A complete version of the |
| Katie McCormick | d178211 | 2011-02-04 15:31:29 -0800 | [diff] [blame] | 492 | snippet 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 |
| Scott Main | 52bfc24 | 2012-02-09 10:09:14 -0800 | [diff] [blame] | 494 | reduce the number of queries a content provider does when its data changes.</li> |
| Katie McCormick | d178211 | 2011-02-04 15:31:29 -0800 | [diff] [blame] | 495 | </ul> |
| 496 | |
| 497 | <p>For information on downloading and installing the SDK samples, see <a |
| 498 | href="http://developer.android.com/resources/samples/get.html"> Getting the |
| 499 | Samples</a>. </p> |
| 500 | |