1page.title=Trình tải 2parent.title=Hoạt động 3parent.link=activities.html 4@jd:body 5<div id="qv-wrapper"> 6<div id="qv"> 7 <h2>Trong tài liệu này</h2> 8 <ol> 9 <li><a href="#summary">Tổng quan về API Trình tải</a></li> 10 <li><a href="#app">Sử dụng các Trình tải trong một Ứng dụng</a> 11 <ol> 12 <li><a href="#requirements"></a></li> 13 <li><a href="#starting">Khởi động một Trình tải</a></li> 14 <li><a href="#restarting">Khởi động lại một Trình tải</a></li> 15 <li><a href="#callback">Sử dụng các Phương pháp Gọi lại LoaderManager</a></li> 16 </ol> 17 </li> 18 <li><a href="#example">Ví dụ</a> 19 <ol> 20 <li><a href="#more_examples">Thêm Ví dụ</a></li> 21 </ol> 22 </li> 23 </ol> 24 25 <h2>Lớp khóa</h2> 26 <ol> 27 <li>{@link android.app.LoaderManager}</li> 28 <li>{@link android.content.Loader}</li> 29 30 </ol> 31 32 <h2>Các mẫu liên quan</h2> 33 <ol> 34 <li> <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderCursor.html"> 35LoaderCursor</a></li> 36 <li> <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderThrottle.html"> 37LoaderThrottle</a></li> 38 </ol> 39 </div> 40</div> 41 42<p>Được giới thiệu trong Android 3.0, trình tải giúp việc tải dữ liệu không đồng bộ 43trong một hoạt động hoặc phân đoạn trở nên dễ dàng. Trình tải có những đặc điểm sau:</p> 44 <ul> 45 <li>Chúng sẵn có cho mọi {@link android.app.Activity} và {@link 46android.app.Fragment}.</li> 47 <li>Chúng cung cấp khả năng tải dữ liệu không đồng bộ.</li> 48 <li>Chúng theo dõi nguồn dữ liệu của mình và chuyển giao kết quả mới khi nội dung 49thay đổi.</li> 50 <li>Chúng tự động kết nối lại với con chạy của trình tải cuối cùng khi được 51tạo lại sau khi cấu hình thay đổi. Vì thế, chúng không cần truy vấn lại dữ liệu 52của mình.</li> 53 </ul> 54 55<h2 id="summary">Tổng quan về API Trình tải</h2> 56 57<p>Có nhiều lớp và giao diện có thể có liên quan trong khi sử dụng 58các trình tải trong một ứng dụng. Chúng được tóm tắt trong bảng này.</p> 59 60<table> 61 <tr> 62 <th>Lớp/Giao diện</th> 63 <th>Mô tả</th> 64 </tr> 65 <tr> 66 <td>{@link android.app.LoaderManager}</td> 67 <td>Một lớp tóm tắt được liên kết với {@link android.app.Activity} hoặc 68{@link android.app.Fragment} để quản lý một hoặc nhiều thực thể {@link 69android.content.Loader}. Nó giúp ứng dụng quản lý 70các thao tác chạy lâu hơn cùng với vòng đời {@link android.app.Activity} 71hoặc {@link android.app.Fragment}; công dụng phổ biến nhất của lớp này là khi dùng với 72{@link android.content.CursorLoader}, tuy nhiên, các ứng dụng được tự do ghi 73trình tải của chính mình để tải các kiểu dữ liệu khác. 74 <br /> 75 <br /> 76 Chỉ có một {@link android.app.LoaderManager} trên mỗi hoạt động hoặc phân đoạn. Nhưng một {@link android.app.LoaderManager} có thể có 77nhiều trình tải.</td> 78 </tr> 79 <tr> 80 <td>{@link android.app.LoaderManager.LoaderCallbacks}</td> 81 <td>Một giao diện gọi lại để một máy khách tương tác với {@link 82android.app.LoaderManager}. Ví dụ, bạn sử dụng phương pháp gọi lại {@link 83android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()} 84để tạo một trình tải mới.</td> 85 </tr> 86 <tr> 87 <td>{@link android.content.Loader}</td> 88 <td>Một lớp tóm tắt có vai trò thực hiện việc tải dữ liệu không đồng bộ. Đây là 89lớp cơ bản cho một trình tải. Thông thường, bạn sẽ sử dụng {@link 90android.content.CursorLoader}, nhưng bạn có thể triển khai lớp con của chính mình. Trong khi 91các trình tải đang hoạt động, chúng sẽ theo dõi nguồn dữ liệu của mình và chuyển giao 92kết quả mới khi nội dung thay đổi. </td> 93 </tr> 94 <tr> 95 <td>{@link android.content.AsyncTaskLoader}</td> 96 <td>Trình tải tóm tắt có chức năng cung cấp {@link android.os.AsyncTask} để thực hiện công việc.</td> 97 </tr> 98 <tr> 99 <td>{@link android.content.CursorLoader}</td> 100 <td>Một lớp con của {@link android.content.AsyncTaskLoader} có chức năng truy vấn 101{@link android.content.ContentResolver} và trả về một {@link 102android.database.Cursor}. Lớp này triển khai giao thức {@link 103android.content.Loader} theo một cách chuẩn hóa để truy vấn các con chạy, 104xây dựng trên {@link android.content.AsyncTaskLoader} để thực hiện truy vấn con chạy 105trên một luồng nền sao cho nó không chặn UI của ứng dụng. Sử dụng 106trình tải này là cách tốt nhất để tải dữ liệu không đồng bộ từ một {@link 107android.content.ContentProvider}, thay vì phải thực hiện một truy vấn được quản lý thông qua 108phân đoạn hoặc các API của hoạt động.</td> 109 </tr> 110</table> 111 112<p>Các lớp và giao diện trong bảng trên là những thành phần thiết yếu 113mà bạn sẽ sử dụng để triển khai một trình tải trong ứng dụng của mình. Bạn sẽ không cần tất cả chúng 114cho từng trình tải mà bạn tạo lập, nhưng bạn sẽ luôn cần một tham chiếu tới {@link 115android.app.LoaderManager} để khởi tạo một trình tải và triển khai 116một lớp {@link android.content.Loader} chẳng hạn như {@link 117android.content.CursorLoader}. Các phần sau đây trình bày với bạn cách sử dụng những 118lớp và giao diện này trong một ứng dụng.</p> 119 120<h2 id ="app">Sử dụng các Trình tải trong một Ứng dụng</h2> 121<p>Phần này mô tả cách sử dụng các trình tải trong một ứng dụng Android. Một 122ứng dụng sử dụng trình tải thường bao gồm:</p> 123<ul> 124 <li>Một {@link android.app.Activity} hoặc {@link android.app.Fragment}.</li> 125 <li>Một thực thể của {@link android.app.LoaderManager}.</li> 126 <li>Một {@link android.content.CursorLoader} để tải dữ liệu được dự phòng bởi một {@link 127android.content.ContentProvider}. Hoặc cách khác, bạn có thể triển khai lớp con 128của {@link android.content.Loader} hoặc {@link android.content.AsyncTaskLoader} của chính mình để tải 129dữ liệu từ một số nguồn khác.</li> 130 <li>Một triển khai cho {@link android.app.LoaderManager.LoaderCallbacks}. 131Đây là nơi bạn tạo trình tải mới và quản lý các tham chiếu của mình tới các 132trình tải hiện có.</li> 133<li>Một cách để hiển thị dữ liệu của trình tải, chẳng hạn như {@link 134android.widget.SimpleCursorAdapter}.</li> 135 <li>Một nguồn dữ liệu, chẳng hạn như một {@link android.content.ContentProvider}, khi sử dụng một 136{@link android.content.CursorLoader}.</li> 137</ul> 138<h3 id="starting">Khởi động một Trình tải</h3> 139 140<p>{@link android.app.LoaderManager} quản lý một hoặc nhiều thực thể {@link 141android.content.Loader} trong một {@link android.app.Activity} hoặc 142{@link android.app.Fragment}. Chỉ có một {@link 143android.app.LoaderManager} trên mỗi hoạt động hoặc phân đoạn.</p> 144 145<p>Thông thường, bạn 146sẽ khởi tạo một {@link android.content.Loader} bên trong phương pháp {@link 147android.app.Activity#onCreate onCreate()} của hoạt động, hoặc trong phương pháp 148{@link android.app.Fragment#onActivityCreated onActivityCreated()} của phân đoạn. Bạn 149làm điều này như sau:</p> 150 151<pre>// Prepare the loader. Either re-connect with an existing one, 152// or start a new one. 153getLoaderManager().initLoader(0, null, this);</pre> 154 155<p>Phương pháp {@link android.app.LoaderManager#initLoader initLoader()} sẽ lấy những 156tham số sau:</p> 157<ul> 158 <li>Một ID duy nhất xác định trình tải. Trong ví dụ này, ID là 0.</li> 159<li>Các tham đối tùy chọn để cung cấp cho trình tải khi 160xây dựng (<code>null</code> trong ví dụ này).</li> 161 162<li>Triển khai {@link android.app.LoaderManager.LoaderCallbacks}, phương pháp mà 163{@link android.app.LoaderManager} gọi để báo cáo các sự kiện trình tải. Trong ví dụ này 164, lớp cục bộ triển khai giao diện {@link 165android.app.LoaderManager.LoaderCallbacks}, vì thế nó chuyển một tham chiếu 166tới chính nó, {@code this}.</li> 167</ul> 168<p>Lệnh gọi {@link android.app.LoaderManager#initLoader initLoader()} đảm bảo rằng một trình tải 169được khởi tạo và hiện hoạt. Nó có hai kết quả có thể xảy ra:</p> 170<ul> 171 <li>Nếu trình tải được quy định bởi ID đã tồn tại, trình tải được tạo lập cuối cùng 172sẽ được sử dụng lại.</li> 173 <li>Nếu trình tải được quy định bởi ID <em>không</em> tồn tại, 174{@link android.app.LoaderManager#initLoader initLoader()} sẽ kích khởi phương pháp 175{@link android.app.LoaderManager.LoaderCallbacks}{@link android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()}. 176Đây là nơi bạn triển khai mã để khởi tạo và trả về một trình tải mới. 177Để bàn thêm, hãy xem phần <a href="#onCreateLoader">onCreateLoader</a>.</li> 178</ul> 179<p>Dù trong trường hợp nào, triển khai {@link android.app.LoaderManager.LoaderCallbacks} 180đã cho được liên kết với trình tải, và sẽ được gọi khi 181trạng thái của trình tải thay đổi. Nếu tại điểm thực hiện lệnh gọi này, hàm gọi đang trong trạng thái 182được khởi động của nó, và trình tải được yêu cầu đã tồn tại và đã khởi tạo 183dữ liệu của nó, khi đó hệ thống sẽ gọi {@link 184android.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()} 185ngay lập tức (trong khi {@link android.app.LoaderManager#initLoader initLoader()}), 186vì thế bạn phải sẵn sàng khi điều này xảy ra. Xem <a href="#onLoadFinished"> 187onLoadFinished</a> để thảo luận thêm về lệnh gọi lại này</p> 188 189<p>Lưu ý rằng phương pháp {@link android.app.LoaderManager#initLoader initLoader()} 190sẽ trả về {@link android.content.Loader} đã được tạo lập, nhưng bạn không 191cần bắt lại một tham chiếu tới nó. {@link android.app.LoaderManager} tự động quản lý 192vòng đời của trình tải. {@link android.app.LoaderManager} 193khởi động và dừng tải khi cần và duy trì trạng thái của trình tải 194và nội dung đi kèm của nó. Như hàm ý, bạn hiếm khi tương tác trực tiếp với các trình tải 195(thông qua một ví dụ về việc sử dụng các phương pháp trình tải để tinh chỉnh hành vi 196của một trình tải, hãy xem ví dụ <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderThrottle.html"> LoaderThrottle</a>). 197Bạn thường sử dụng nhất là các phương pháp {@link 198android.app.LoaderManager.LoaderCallbacks} để can thiệp vào tiến trình tải 199khi diễn ra một sự kiện đặc biệt. Để thảo luận thêm về chủ đề này, hãy xem phần <a href="#callback">Sử dụng Phương pháp Gọi lại LoaderManager</a>.</p> 200 201<h3 id="restarting">Khởi động lại một Trình tải</h3> 202 203<p>Khi bạn sử dụng {@link android.app.LoaderManager#initLoader initLoader()}, như 204trình bày bên trên, nó sử dụng một trình tải hiện hữu với ID được quy định nếu có. 205Nếu không có, nó sẽ tạo một trình tải. Nhưng đôi khi bạn muốn bỏ dữ liệu cũ của mình 206và bắt đầu lại.</p> 207 208<p>Để bỏ dữ liệu cũ của mình, hãy sử dụng {@link 209android.app.LoaderManager#restartLoader restartLoader()}. Ví dụ, việc 210triển khai {@link android.widget.SearchView.OnQueryTextListener} này sẽ khởi động lại 211trình tải khi truy vấn của người dùng thay đổi. Trình tải cần được khởi động lại sao cho 212nó có thể sử dụng bộ lọc tìm kiếm được điều chỉnh để thực hiện một truy vấn mới:</p> 213 214<pre> 215public boolean onQueryTextChanged(String newText) { 216 // Called when the action bar search text has changed. Update 217 // the search filter, and restart the loader to do a new query 218 // with this filter. 219 mCurFilter = !TextUtils.isEmpty(newText) ? newText : null; 220 getLoaderManager().restartLoader(0, null, this); 221 return true; 222}</pre> 223 224<h3 id="callback">Sử dụng các Phương pháp Gọi lại LoaderManager</h3> 225 226<p>{@link android.app.LoaderManager.LoaderCallbacks} là một giao diện gọi lại 227cho phép một máy khách tương tác với {@link android.app.LoaderManager}. </p> 228<p>Các trình tải, đặc biệt là {@link android.content.CursorLoader}, được kỳ vọng sẽ 229giữ lại dữ liệu của chúng sau khi bị dừng. Điều này cho phép ứng dụng giữ lại 230dữ liệu của chúng qua hoạt động hoặc các phương pháp {@link android.app.Activity#onStop 231onStop()} và {@link android.app.Activity#onStart onStart()} của phân đoạn, sao cho khi 232người dùng quay lại một ứng dụng, họ không phải chờ dữ liệu 233tải lại. Bạn sử dụng các phương pháp {@link android.app.LoaderManager.LoaderCallbacks} 234khi cần biết khi nào thì nên tạo một trình tải mới, và để thông báo với ứng dụng khi nào 235 thì đến lúc để dừng sử dụng dữ liệu của một trình tải.</p> 236 237<p>{@link android.app.LoaderManager.LoaderCallbacks} bao gồm những phương pháp 238sau:</p> 239<ul> 240 <li>{@link android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()} — 241Khởi tạo và trả về một {@link android.content.Loader} mới cho ID đã cho. 242</li></ul> 243<ul> 244 <li> {@link android.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()} 245— Được gọi khi một trình tải được tạo trước đó đã hoàn tất việc tải. 246</li></ul> 247<ul> 248 <li>{@link android.app.LoaderManager.LoaderCallbacks#onLoaderReset onLoaderReset()} 249 — Được gọi khi một trình tải được tạo trước đó đang được đặt lại, vì thế mà khiến dữ liệu 250của nó không sẵn có. 251</li> 252</ul> 253<p>Những phương pháp này được mô tả chi tiết hơn trong các phần sau.</p> 254 255<h4 id ="onCreateLoader">onCreateLoader</h4> 256 257<p>Khi bạn định truy cập một trình tải (ví dụ, thông qua {@link 258android.app.LoaderManager#initLoader initLoader()}), nó kiểm tra xem 259trình tải được quy định bởi ID có tồn tại không. Nếu không, nó sẽ kích khởi phương pháp {@link 260android.app.LoaderManager.LoaderCallbacks} {@link 261android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()}. Đây 262là lúc bạn tạo một trình tải mới. Thông thường sẽ có một {@link 263android.content.CursorLoader}, nhưng bạn có thể triển khai lớp con {@link 264android.content.Loader} của chính mình. </p> 265 266<p>Trong ví dụ này, phương pháp gọi lại {@link 267android.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()} 268sẽ tạo một {@link android.content.CursorLoader}. Bạn phải xây dựng 269{@link android.content.CursorLoader} bằng cách sử dụng phương pháp hàm dựng của nó mà yêu cầu 270trọn bộ thông tin cần thiết để thực hiện một truy vấn tới {@link 271android.content.ContentProvider}. Cụ thể, nó cần:</p> 272<ul> 273 <li><em>uri</em> — URI của nội dung cần truy xuất. </li> 274 <li><em>dự thảo</em> — Một danh sách các cột sẽ trả về. Việc chuyển 275<code>null</code> sẽ trả về tất cả cột, điều này không hiệu quả. </li> 276 <li><em>lựa chọn</em> — Một bộ lọc khai báo các hàng nào sẽ trả về, 277có định dạng như một mệnh đề SQL WHERE (không gồm chính mệnh đề WHERE). Việc chuyển 278<code>null</code> sẽ trả về tất cả hàng cho URI đã cho. </li> 279 <li><em>selectionArgs</em> — Bạn có thể thêm ?s vào lựa chọn, 280chúng sẽ được thay thế bằng các giá trị từ <em>selectionArgs</em>, theo thứ tự xuất hiện trong 281lựa chọn. Giá trị sẽ được gắn kết thành các Xâu. </li> 282 <li><em>sortOrder</em> — Cách sắp xếp thứ tự các hàng, được định dạng như một mệnh đề SQL 283ORDER BY (không bao gồm chính mệnh đề ORDER BY). Việc chuyển <code>null</code> sẽ 284sử dụng thứ tự sắp xếp mặc định, điều này có thể dẫn đến kết quả không theo thứ tự.</li> 285</ul> 286<p>Ví dụ:</p> 287<pre> 288 // If non-null, this is the current filter the user has provided. 289String mCurFilter; 290... 291public Loader<Cursor> onCreateLoader(int id, Bundle args) { 292 // This is called when a new Loader needs to be created. This 293 // sample only has one Loader, so we don't care about the ID. 294 // First, pick the base URI to use depending on whether we are 295 // currently filtering. 296 Uri baseUri; 297 if (mCurFilter != null) { 298 baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, 299 Uri.encode(mCurFilter)); 300 } else { 301 baseUri = Contacts.CONTENT_URI; 302 } 303 304 // Now create and return a CursorLoader that will take care of 305 // creating a Cursor for the data being displayed. 306 String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND (" 307 + Contacts.HAS_PHONE_NUMBER + "=1) AND (" 308 + Contacts.DISPLAY_NAME + " != '' ))"; 309 return new CursorLoader(getActivity(), baseUri, 310 CONTACTS_SUMMARY_PROJECTION, select, null, 311 Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC"); 312}</pre> 313<h4 id="onLoadFinished">onLoadFinished</h4> 314 315<p>Phương pháp này được gọi khi một trình tải được tạo trước đó đã hoàn thành việc tải của mình. 316Phương pháp này được bảo đảm sẽ được gọi trước khi giải phóng dữ liệu cuối cùng 317được cung cấp cho trình tải này. Tại điểm này, bạn nên loại bỏ mọi trường hợp sử dụng 318dữ liệu cũ (do nó sẽ được giải phóng sớm), nhưng không nên 319tự mình giải phóng dữ liệu do trình tải sở hữu dữ liệu và sẽ đảm nhận việc này.</p> 320 321 322<p>Trình tải sẽ giải phóng dữ liệu sau khi nó biết ứng dụng đang không còn 323sử dụng nó nữa. Ví dụ, nếu dữ liệu là một con chạy từ một {@link 324android.content.CursorLoader}, bạn không nên tự mình gọi {@link 325android.database.Cursor#close close()} trên dữ liệu đó. Nếu con chạy đang được đặt 326trong một {@link android.widget.CursorAdapter}, bạn nên sử dụng phương pháp {@link 327android.widget.SimpleCursorAdapter#swapCursor swapCursor()} sao cho 328 {@link android.database.Cursor} cũ không bị đóng. Ví dụ:</p> 329 330<pre> 331// This is the Adapter being used to display the list's data.<br 332/>SimpleCursorAdapter mAdapter; 333... 334 335public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 336 // Swap the new cursor in. (The framework will take care of closing the 337 // old cursor once we return.) 338 mAdapter.swapCursor(data); 339}</pre> 340 341<h4 id="onLoaderReset">onLoaderReset</h4> 342 343<p>Phương pháp này được gọi khi một trình tải được tạo trước đó đang được đặt lại, vì thế mà khiến 344dữ liệu của nó không sẵn có. Lệnh gọi lại này cho phép bạn tìm hiểu xem khi nào thì dữ liệu 345sẽ được giải phóng để bạn có thể loại bỏ tham chiếu của mình tới nó. </p> 346<p>Sự triển khai này gọi ra 347{@link android.widget.SimpleCursorAdapter#swapCursor swapCursor()} 348với một giá trị <code>null</code>:</p> 349 350<pre> 351// This is the Adapter being used to display the list's data. 352SimpleCursorAdapter mAdapter; 353... 354 355public void onLoaderReset(Loader<Cursor> loader) { 356 // This is called when the last Cursor provided to onLoadFinished() 357 // above is about to be closed. We need to make sure we are no 358 // longer using it. 359 mAdapter.swapCursor(null); 360}</pre> 361 362 363<h2 id="example">Ví dụ</h2> 364 365<p>Lấy một ví dụ, sau đây là triển khai đầy đủ của {@link 366android.app.Fragment} có chức năng hiển thị một {@link android.widget.ListView} chứa 367kết quả của một truy vấn đối với trình cung cấp nội dung danh bạ. Nó sử dụng một {@link 368android.content.CursorLoader} để quản lý truy vấn trên trình cung cấp.</p> 369 370<p>Để một ứng dụng truy cập danh bạ của một người dùng, như minh họa trong ví dụ này, bản kê khai 371của nó phải bao gồm quyền 372{@link android.Manifest.permission#READ_CONTACTS READ_CONTACTS}.</p> 373 374<pre> 375public static class CursorLoaderListFragment extends ListFragment 376 implements OnQueryTextListener, LoaderManager.LoaderCallbacks<Cursor> { 377 378 // This is the Adapter being used to display the list's data. 379 SimpleCursorAdapter mAdapter; 380 381 // If non-null, this is the current filter the user has provided. 382 String mCurFilter; 383 384 @Override public void onActivityCreated(Bundle savedInstanceState) { 385 super.onActivityCreated(savedInstanceState); 386 387 // Give some text to display if there is no data. In a real 388 // application this would come from a resource. 389 setEmptyText("No phone numbers"); 390 391 // We have a menu item to show in action bar. 392 setHasOptionsMenu(true); 393 394 // Create an empty adapter we will use to display the loaded data. 395 mAdapter = new SimpleCursorAdapter(getActivity(), 396 android.R.layout.simple_list_item_2, null, 397 new String[] { Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS }, 398 new int[] { android.R.id.text1, android.R.id.text2 }, 0); 399 setListAdapter(mAdapter); 400 401 // Prepare the loader. Either re-connect with an existing one, 402 // or start a new one. 403 getLoaderManager().initLoader(0, null, this); 404 } 405 406 @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 407 // Place an action bar item for searching. 408 MenuItem item = menu.add("Search"); 409 item.setIcon(android.R.drawable.ic_menu_search); 410 item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); 411 SearchView sv = new SearchView(getActivity()); 412 sv.setOnQueryTextListener(this); 413 item.setActionView(sv); 414 } 415 416 public boolean onQueryTextChange(String newText) { 417 // Called when the action bar search text has changed. Update 418 // the search filter, and restart the loader to do a new query 419 // with this filter. 420 mCurFilter = !TextUtils.isEmpty(newText) ? newText : null; 421 getLoaderManager().restartLoader(0, null, this); 422 return true; 423 } 424 425 @Override public boolean onQueryTextSubmit(String query) { 426 // Don't care about this. 427 return true; 428 } 429 430 @Override public void onListItemClick(ListView l, View v, int position, long id) { 431 // Insert desired behavior here. 432 Log.i("FragmentComplexList", "Item clicked: " + id); 433 } 434 435 // These are the Contacts rows that we will retrieve. 436 static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] { 437 Contacts._ID, 438 Contacts.DISPLAY_NAME, 439 Contacts.CONTACT_STATUS, 440 Contacts.CONTACT_PRESENCE, 441 Contacts.PHOTO_ID, 442 Contacts.LOOKUP_KEY, 443 }; 444 public Loader<Cursor> onCreateLoader(int id, Bundle args) { 445 // This is called when a new Loader needs to be created. This 446 // sample only has one Loader, so we don't care about the ID. 447 // First, pick the base URI to use depending on whether we are 448 // currently filtering. 449 Uri baseUri; 450 if (mCurFilter != null) { 451 baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, 452 Uri.encode(mCurFilter)); 453 } else { 454 baseUri = Contacts.CONTENT_URI; 455 } 456 457 // Now create and return a CursorLoader that will take care of 458 // creating a Cursor for the data being displayed. 459 String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND (" 460 + Contacts.HAS_PHONE_NUMBER + "=1) AND (" 461 + Contacts.DISPLAY_NAME + " != '' ))"; 462 return new CursorLoader(getActivity(), baseUri, 463 CONTACTS_SUMMARY_PROJECTION, select, null, 464 Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC"); 465 } 466 467 public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 468 // Swap the new cursor in. (The framework will take care of closing the 469 // old cursor once we return.) 470 mAdapter.swapCursor(data); 471 } 472 473 public void onLoaderReset(Loader<Cursor> loader) { 474 // This is called when the last Cursor provided to onLoadFinished() 475 // above is about to be closed. We need to make sure we are no 476 // longer using it. 477 mAdapter.swapCursor(null); 478 } 479}</pre> 480<h3 id="more_examples">Thêm Ví dụ</h3> 481 482<p>Có một vài mẫu khác trong <strong>ApiDemos</strong> để 483minh họa cách sử dụng các trình tải:</p> 484<ul> 485 <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderCursor.html"> 486LoaderCursor</a> — Một phiên bản hoàn chỉnh của 487đoạn mã HTML trình bày ở trên.</li> 488 <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderThrottle.html"> LoaderThrottle</a> — Một ví dụ về cách sử dụng điều chỉnh để giảm 489số truy vấn mà một trình cung cấp nội dung thực hiện khi dữ liệu của nó thay đổi.</li> 490</ul> 491 492<p>Để biết thông tin về việc tải xuống và cài đặt các mẫu SDK, hãy xem phần <a href="http://developer.android.com/resources/samples/get.html"> Tải 493Mẫu</a>. </p> 494 495