1 page.title=Handling the Results 2 trainingnavtop=true 3 startpage=true 4 5 @jd:body 6 7 <!-- This is the training bar --> 8 <div id="tb-wrapper"> 9 <div id="tb"> 10 <h2>This lesson teaches you to</h2> 11 <ol> 12 <li> 13 <a href="#HandleResults">Handle Query Results</a> 14 </li> 15 <li> 16 <a href="#HandleReset">Delete Old Cursor References</a></li> 17 </ol> 18 19 <h2>Try it out</h2> 20 <div class="download-box"> 21 <a href="{@docRoot}shareables/training/ThreadSample.zip" class="button">Download the sample</a> 22 <p class="filename">ThreadSample.zip</p> 23 </div> 24 25 </div> 26 </div> 27 28 <p> 29 As shown in the previous lesson, you should begin loading your data with a 30 {@link android.support.v4.content.CursorLoader} in your implementation of 31 {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onCreateLoader 32 onCreateLoader()}. The loader then provides the query results to your 33 {@link android.app.Activity} or {@link android.support.v4.app.FragmentActivity} in your 34 implementation of {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoadFinished 35 LoaderCallbacks.onLoadFinished()}. One of the incoming arguments to this method is a 36 {@link android.database.Cursor} containing the query results. You can use this object to 37 update your data display or do further processing. 38 </p> 39 <p> 40 Besides 41 {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()} and 42 {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()}, 43 you also have to implement 44 {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoaderReset onLoaderReset()}. 45 This method is invoked when {@link android.support.v4.content.CursorLoader} detects 46 that data associated with the {@link android.database.Cursor} has changed. When the 47 data changes, the framework also re-runs the current query. 48 </p> 49 <h2 id="HandleResults">Handle Query Results</h2> 50 <p> 51 To display {@link android.database.Cursor} data returned by 52 {@link android.support.v4.content.CursorLoader}, use a 53 {@link android.view.View} class that implements {@link android.widget.AdapterView} and 54 provide the view with an adapter that implements 55 {@link android.support.v4.widget.CursorAdapter}. The system then automatically moves data from 56 the {@link android.database.Cursor} to the view. 57 </p> 58 <p> 59 You can set up the linkage between the view and adapter before you have any data to display, 60 and then move a {@link android.database.Cursor} into the adapter in the 61 {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()} 62 method. As soon as you move the {@link android.database.Cursor} into the adapter, the 63 system automatically updates the view. This also happens if you change the contents of the 64 {@link android.database.Cursor}. 65 </p> 66 <p> 67 For example: 68 </p> 69 <pre> 70 public String[] mFromColumns = { 71 DataProviderContract.IMAGE_PICTURENAME_COLUMN 72 }; 73 public int[] mToFields = { 74 R.id.PictureName 75 }; 76 // Gets a handle to a List View 77 ListView mListView = (ListView) findViewById(R.id.dataList); 78 /* 79 * Defines a SimpleCursorAdapter for the ListView 80 * 81 */ 82 SimpleCursorAdapter mAdapter = 83 new SimpleCursorAdapter( 84 this, // Current context 85 R.layout.list_item, // Layout for a single row 86 null, // No Cursor yet 87 mFromColumns, // Cursor columns to use 88 mToFields, // Layout fields to use 89 0 // No flags 90 ); 91 // Sets the adapter for the view 92 mListView.setAdapter(mAdapter); 93 ... 94 /* 95 * Defines the callback that {@link android.support.v4.content.CursorLoader} calls 96 * when it's finished its query 97 */ 98 @Override 99 public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { 100 ... 101 /* 102 * Moves the query results into the adapter, causing the 103 * ListView fronting this adapter to re-display 104 */ 105 mAdapter.changeCursor(cursor); 106 } 107 </pre> 108 <h2 id="HandleReset">Delete Old Cursor References</h2> 109 <p> 110 The {@link android.support.v4.content.CursorLoader} is reset whenever its 111 {@link android.database.Cursor} becomes invalid. This usually occurs because the data associated 112 with the {@link android.database.Cursor} has changed. Before re-running the query, 113 the framework calls your implementation of 114 {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoaderReset onLoaderReset()}. In 115 this callback, you should delete all references to the current {@link android.database.Cursor} 116 in order to prevent memory leaks. Once 117 {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoaderReset onLoaderReset()} 118 finishes, {@link android.support.v4.content.CursorLoader} re-runs its query. 119 </p> 120 <p> 121 For example: 122 </p> 123 <pre> 124 /* 125 * Invoked when the CursorLoader is being reset. For example, this is 126 * called if the data in the provider changes and the Cursor becomes stale. 127 */ 128 @Override 129 public void onLoaderReset(Loader<Cursor> loader) { 130 131 /* 132 * Clears out the adapter's reference to the Cursor. 133 * This prevents memory leaks. 134 */ 135 mAdapter.changeCursor(null); 136 } 137 </pre> 138