Kể từ Android 9 (API cấp 28), trình tải sẽ không được dùng nữa. Lựa chọn được đề xuất cho
xử lý việc tải dữ liệu trong khi xử lý vòng đời Activity
và Fragment
là sử dụng một
tổ hợp các đối tượng ViewModel
và LiveData
.
Các mô hình khung hiển thị vẫn tồn tại sau khi thay đổi cấu hình, chẳng hạn như trình tải, nhưng với
ít mã nguyên mẫu hơn. LiveData
cung cấp cách nhận biết vòng đời để tải dữ liệu mà bạn có thể sử dụng lại trong
nhiều mô hình hiển thị. Bạn cũng có thể kết hợp LiveData
bằng cách sử dụng
MediatorLiveData
.
Bất kỳ truy vấn nào có thể quan sát được, chẳng hạn như truy vấn từ
Cơ sở dữ liệu Room, có thể dùng đ�� quan sát các thay đổi
đối với dữ liệu.
Bạn cũng có thể dùng ViewModel
và LiveData
trong trường hợp bạn không có quyền truy cập
vào LoaderManager
, chẳng hạn như trong
Service
. Sử dụng cả hai trong
tandem giúp bạn dễ dàng truy cập vào dữ liệu mà ứng dụng của bạn cần mà không phải xử lý giao diện người dùng
vòng đời. Để tìm hiểu thêm về LiveData
, hãy xem
Tổng quan về LiveData
. Để tìm hiểu thêm về
ViewModel
, xem thông tin tổng quan về ViewModel
.
Loader API cho phép bạn tải dữ liệu từ
nhà cung cấp nội dung
hoặc nguồn dữ liệu khác để hiển thị trong FragmentActivity
hoặc Fragment
.
Nếu không có trình tải, bạn có thể gặp phải một số vấn đề sau:
- Nếu bạn tìm nạp dữ liệu trực tiếp trong hoạt động hoặc mảnh, người dùng của bạn thiếu phản hồi do có khả năng hoạt động chậm các truy vấn từ luồng giao diện người dùng.
- Nếu bạn tìm nạp dữ liệu từ một chuỗi khác, có thể là bằng
AsyncTask
, thì bạn chịu trách nhiệm quản lý cả chuỗi đó và luồng giao diện người dùng thông qua các sự kiện trong vòng đời mảnh hoặc hoạt động khác nhau, chẳng hạn nhưonDestroy()
và các thay đổi về cấu hình.
Trình tải giải quyết những vấn đề này và đi kèm những lợi ích khác:
- Trình tải chạy trên các luồng riêng biệt để ngăn giao diện người dùng bị chậm hoặc không phản hồi.
- Trình tải đơn giản hoá việc quản lý luồng bằng cách cung cấp các phương thức gọi lại khi sự kiện xảy ra.
- Trình tải vẫn duy trì và lưu kết quả vào bộ nhớ đệm khi cấu hình thay đổi để ngăn chặn truy vấn trùng lặp.
- Trình tải có thể triển khai một trình quan sát để theo dõi những thay đổi trong
nguồn dữ liệu. Ví dụ:
CursorLoader
tự động đăng ký mộtContentObserver
để kích hoạt quá trình tải lại khi dữ liệu thay đổi.
Tóm tắt về Loader API
Có thể có nhiều lớp và giao diện cũng sẽ được đưa vào khi sử dụng trình tải trong ứng dụng. Các chỉ số này được tóm tắt trong bảng sau:
Lớp/Giao diện | Mô tả |
---|---|
LoaderManager |
Một lớp trừu tượng liên kết với FragmentActivity hoặc
Fragment để quản lý một hoặc nhiều
Thực thể Loader . Chỉ có một
LoaderManager cho mỗi hoạt động hoặc mảnh, nhưng có một
LoaderManager có thể quản lý nhiều trình tải.
Để nhận Để bắt đầu tải dữ liệu từ một trình tải, hãy gọi một trong hai
|
LoaderManager.LoaderCallbacks |
Giao diện này chứa phương thức gọi lại sẽ được gọi khi
sự kiện trình tải xảy ra. Giao diện này xác định 3 phương thức gọi lại:
initLoader() hoặc
restartLoader() .
|
Loader |
Trình tải thực hiện việc tải dữ liệu. Lớp này mang tính trừu tượng và phân phát
làm lớp cơ sở cho tất cả trình tải. Bạn có thể trực tiếp thêm lớp con
Loader hoặc sử dụng một trong các tính năng tích hợp sẵn sau đây
lớp con để đơn giản hoá việc triển khai:
|
Các phần sau đây cho bạn biết cách sử dụng các lớp và giao diện trong một ứng dụng.
Sử dụng trình tải trong một ứng dụng
Phần này mô tả cách sử dụng trình tải trong ứng dụng Android. Một ứng dụng sử dụng trình tải thường bao gồm những nội dung sau:
FragmentActivity
hoặcFragment
.- Một thực thể của
LoaderManager
. CursorLoader
để tải dữ liệu doContentProvider
hỗ trợ. Ngoài ra, bạn có thể triển khai lớp con của riêng mình từLoader
hoặcAsyncTaskLoader
đến tải dữ liệu từ một số nguồn khác.- Cách triển khai cho
LoaderManager.LoaderCallbacks
. Đây là nơi bạn tạo trình tải mới và quản lý thông tin tham chiếu đến trình tải. - Một cách hiển thị dữ liệu của trình tải, chẳng hạn như
SimpleCursorAdapter
. - Một nguồn dữ liệu, chẳng hạn như
ContentProvider
, khi sử dụng mộtCursorLoader
Khởi động một trình tải
LoaderManager
quản lý một hoặc nhiều thực thể Loader
trong một FragmentActivity
hoặc
Fragment
. Chỉ có một LoaderManager
cho mỗi hoạt động hoặc mảnh.
Bạn thường
khởi chạy Loader
trong phương thức onCreate()
của hoạt động hoặc
onCreate()
. Bạn
thực hiện việc này như sau:
Kotlin
supportLoaderManager.initLoader(0, null, this)
Java
// Prepare the loader. Either re-connect with an existing one, // or start a new one. getSupportLoaderManager().initLoader(0, null, this);
Phương thức initLoader()
nhận
các thông số sau:
- Mã nhận dạng duy nhất giúp xác định trình tải. Trong ví dụ này, mã nhận dạng là
0
. - Các đối số không bắt buộc đ�� cung cấp cho trình tải tại
cấu trúc (trong ví dụ này là
null
). - Triển khai
LoaderManager.LoaderCallbacks
, các lệnh gọiLoaderManager
để báo cáo sự kiện của trình tải. Trong phần này ví dụ: lớp cục bộ triển khai giao diệnLoaderManager.LoaderCallbacks
, vì vậy, lớp này truyền một tham chiếu với chính nó,this
.
Lệnh gọi initLoader()
đảm bảo rằng một trình tải
đã được khởi tạo và đang hoạt động. Điều này có thể có hai kết quả:
- Nếu đã có trình tải mà mã nhận dạng chỉ định, thì trình tải được tạo gần đây nhất được sử dụng lại.
- Nếu trình tải do mã nhận dạng chỉ định không tồn tại,
initLoader()
sẽ kích hoạtLoaderManager.LoaderCallbacks
phương thứconCreateLoader()
. Đây là nơi bạn triển khai mã để tạo thực thể và trả về một trình tải m��i. Để thảo luận thêm, hãy xem phần vềonCreateLoader
.
Trong cả hai trường hợp, LoaderManager.LoaderCallbacks
đã cho
triển khai được liên kết với trình tải và được gọi khi
các thay đổi về trạng thái của trình tải. Nếu, tại thời điểm của cuộc gọi này, phương thức gọi đang ở
trạng thái bắt đầu và trình tải được yêu cầu đã tồn tại và đã tạo
dữ liệu thì hệ thống sẽ gọi onLoadFinished()
ngay lập tức, trong initLoader()
. Bạn phải chuẩn bị cho điều này xảy ra. Để thảo luận thêm về lệnh gọi lại này, hãy xem phần về
onLoadFinished
.
Phương thức initLoader()
trả về Loader
được tạo,
nhưng bạn không cần phải thu thập thông tin tham chiếu đến đối tượng đó. LoaderManager
quản lý
vòng đời của trình tải. LoaderManager
bắt đầu và ngừng tải khi cần thiết và duy trì trạng thái của trình tải
và nội dung liên quan.
Như điều này có nghĩa là bạn hiếm khi tương tác với trình tải
trực tiếp.
Bạn thường sử dụng các phương thức LoaderManager.LoaderCallbacks
để can thiệp vào quá trình tải
khi các sự kiện cụ thể xảy ra. Để thảo luận thêm về chủ đề này, hãy xem phần Sử dụng lệnh gọi lại LoaderManager.
Khởi động lại trình tải
Khi bạn sử dụng initLoader()
, như
hiển thị trong phần trước, nó sử dụng một trình tải hiện có cùng với mã nhận dạng được chỉ định (nếu có).
Nếu chưa có, hệ thống sẽ tạo một tài khoản. Nhưng đôi khi bạn muốn loại bỏ dữ liệu cũ
và bắt đầu lại.
Để loại bỏ dữ liệu cũ, hãy sử dụng restartLoader()
. Ví dụ: như sau
quá trình triển khai SearchView.OnQueryTextListener
khởi động lại
trình tải khi truy vấn của người dùng thay đổi. Bạn cần khởi động lại trình tải để
để có thể sử dụng bộ lọc tìm kiếm đã sửa đổi để tạo một truy vấn mới.
Kotlin
fun onQueryTextChanged(newText: String?): Boolean { // 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. curFilter = if (newText?.isNotEmpty() == true) newText else null supportLoaderManager.restartLoader(0, null, this) return true }
Java
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. curFilter = !TextUtils.isEmpty(newText) ? newText : null; getSupportLoaderManager().restartLoader(0, null, this); return true; }
Sử dụng các lệnh gọi lại LoaderManager
LoaderManager.LoaderCallbacks
là giao diện gọi lại
cho phép ứng dụng tương tác với LoaderManager
.
Các trình tải, cụ thể là CursorLoader
, dự kiến sẽ
giữ lại dữ liệu sau khi bị ngừng. Điều này cho phép các ứng dụng giữ nguyên
trên các phương thức onStop()
và onStart()
của hoạt động hoặc mảnh để
khi người dùng quay lại một ứng dụng, họ không phải đợi dữ liệu
tải lại.
Bạn dùng các phương thức LoaderManager.LoaderCallbacks
để biết thời điểm tạo trình tải mới và cho ứng dụng biết khi nào
đã đến lúc ngừng sử dụng dữ liệu của trình tải.
LoaderManager.LoaderCallbacks
bao gồm những điều sau
phương thức:
onCreateLoader()
: tạo thực thể và trả về mộtLoader
mới cho mã nhận dạng đã cho.
-
onLoadFinished()
: được gọi khi một trình tải đã tạo trước đó hoàn tất quá trình tải.
onLoaderReset()
: được gọi khi một trình tải đã tạo trước đó được đặt lại, khiến cho không có sẵn dữ liệu.
Các phương pháp này được mô tả chi tiết hơn trong các phần sau.
onCreateLoader
Khi bạn cố gắng truy cập vào một trình tải, chẳng hạn như thông qua initLoader()
, trình tải này sẽ kiểm tra xem liệu
trình tải được chỉ định theo mã nhận dạng đã tồn tại. Nếu không, lệnh này sẽ kích hoạt phương thức LoaderManager.LoaderCallbacks
onCreateLoader()
. Chiến dịch này
là nơi bạn tạo một trình tải mới. Thường thì đây là CursorLoader
, nhưng bạn có thể triển khai lớp con Loader
của riêng mình.
Trong ví dụ sau, onCreateLoader()
phương thức gọi lại này tạo một CursorLoader
bằng phương thức hàm khởi tạo, phương thức này
yêu cầu tập hợp thông tin hoàn chỉnh cần thiết để thực hiện truy vấn đối với ContentProvider
. Cụ thể, ứng dụng này cần:
- uri: URI cho nội dung cần truy xuất.
- projection: danh sách các cột sẽ trả về. Cầu thủ chuyền bóng
null
trả về tất cả các cột và điều này không hiệu quả. - selection: bộ lọc khai báo hàng nào cần trả về,
có định dạng là mệnh đề SQL WHERE (không bao gồm chính WHERE). Cầu thủ chuyền bóng
null
trả về tất cả các hàng cho URI đã cho. - selectionArgs: nếu bạn đưa dấu ?s vào lựa chọn, chúng được thay thế bằng các giá trị lấy từ selectionArgs theo thứ tự xuất hiện trong lựa chọn. Các giá trị được liên kết dưới dạng chuỗi.
- sortOrder: cách sắp xếp các hàng, được định dạng dưới dạng SQL
Mệnh đề ORDER BY (không bao gồm chính ORDER BY). Chuyền thành công
null
sử dụng thứ tự sắp xếp mặc định, có thể không theo thứ tự.
Kotlin
// If non-null, this is the current filter the user has provided. private var curFilter: String? = null ... override fun onCreateLoader(id: Int, args: Bundle?): Loader<Cursor> { // 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. val baseUri: Uri = if (curFilter != null) { Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI, Uri.encode(curFilter)) } else { ContactsContract.Contacts.CONTENT_URI } // Now create and return a CursorLoader that will take care of // creating a Cursor for the data being displayed. val select: String = "((${Contacts.DISPLAY_NAME} NOTNULL) AND (" + "${Contacts.HAS_PHONE_NUMBER}=1) AND (" + "${Contacts.DISPLAY_NAME} != ''))" return (activity as? Context)?.let { context -> CursorLoader( context, baseUri, CONTACTS_SUMMARY_PROJECTION, select, null, "${Contacts.DISPLAY_NAME} COLLATE LOCALIZED ASC" ) } ?: throw Exception("Activity cannot be null") }
Java
// If non-null, this is the current filter the user has provided. String curFilter; ... 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 (curFilter != null) { baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, Uri.encode(curFilter)); } 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"); }
onLoadĐã hoàn tất
Phương thức này được gọi khi một trình tải đã tạo trước đó hoàn tất lượt tải. Phương thức này đảm bảo sẽ được gọi trước khi phát hành dữ liệu gần đây nhất được cung cấp cho trình tải này. Tại thời điểm này, hãy xoá tất cả việc sử dụng dữ liệu cũ vì dữ liệu này sắp được phát hành. Nhưng không phát hành dữ liệu chính bạn—trình tải sở hữu và xử lý việc đó.
Trình tải sẽ huỷ bỏ dữ liệu sau khi biết rằng ứng dụng không còn tồn tại
đang sử dụng nó. Ví dụ: nếu dữ liệu là con trỏ từ CursorLoader
,
đừng tự gọi close()
. Nếu con trỏ đang
được đặt trong CursorAdapter
, hãy sử dụng phương thức swapCursor()
để
Cursor
cũ chưa đóng, như trong ví dụ sau:
Kotlin
private lateinit var adapter: SimpleCursorAdapter ... override fun onLoadFinished(loader: Loader<Cursor>, data: Cursor?) { // Swap the new cursor in. (The framework will take care of closing the // old cursor once we return.) adapter.swapCursor(data) }
Java
// This is the Adapter being used to display the list's data. SimpleCursorAdapter adapter; ... 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.) adapter.swapCursor(data); }
onLoaderReset
Phương thức này được gọi khi đặt lại một trình tải đã tạo trước đó, do đó làm cho dữ liệu không có sẵn. Lệnh gọi lại này cho phép bạn tìm hiểu thời điểm dữ liệu được sắp được phát hành để bạn có thể xoá tham chiếu đến tệp đó.
Phương thức triển khai này gọi
swapCursor()
có giá trị null
:
Kotlin
private lateinit var adapter: SimpleCursorAdapter ... override fun onLoaderReset(loader: Loader<Cursor>) { // 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. adapter.swapCursor(null) }
Java
// This is the Adapter being used to display the list's data. SimpleCursorAdapter adapter; ... 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. adapter.swapCursor(null); }
Ví dụ
Ví dụ: dưới đây là cách triển khai đầy đủ của Fragment
hiển thị ListView
chứa
các kết quả của một truy vấn với trình cung cấp nội dung danh bạ. Lớp này sử dụng CursorLoader
để quản lý truy vấn trên trình cung cấp.
Do ví dụ này là từ một ứng dụng để truy cập vào danh bạ của người dùng,
tệp kê khai phải bao gồm quyền
READ_CONTACTS
.
Kotlin
private val CONTACTS_SUMMARY_PROJECTION: Array<String> = arrayOf( Contacts._ID, Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS, Contacts.CONTACT_PRESENCE, Contacts.PHOTO_ID, Contacts.LOOKUP_KEY ) class CursorLoaderListFragment : ListFragment(), SearchView.OnQueryTextListener, LoaderManager.LoaderCallbacks<Cursor> { // This is the Adapter being used to display the list's data. private lateinit var mAdapter: SimpleCursorAdapter // If non-null, this is the current filter the user has provided. private var curFilter: String? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Prepare the loader. Either re-connect with an existing one, // or start a new one. loaderManager.initLoader(0, null, this) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, 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 = SimpleCursorAdapter(activity, android.R.layout.simple_list_item_2, null, arrayOf(Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS), intArrayOf(android.R.id.text1, android.R.id.text2), 0 ) listAdapter = mAdapter } override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { // Place an action bar item for searching. menu.add("Search").apply { setIcon(android.R.drawable.ic_menu_search) setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM) actionView = SearchView(activity).apply { setOnQueryTextListener(this@CursorLoaderListFragment) } } } override fun onQueryTextChange(newText: String?): Boolean { // 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. curFilter = if (newText?.isNotEmpty() == true) newText else null loaderManager.restartLoader(0, null, this) return true } override fun onQueryTextSubmit(query: String): Boolean { // Don't care about this. return true } override fun onListItemClick(l: ListView, v: View, position: Int, id: Long) { // Insert desired behavior here. Log.i("FragmentComplexList", "Item clicked: $id") } override fun onCreateLoader(id: Int, args: Bundle?): Loader<Cursor> { // 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. val baseUri: Uri = if (curFilter != null) { Uri.withAppendedPath(Contacts.CONTENT_URI, Uri.encode(curFilter)) } else { Contacts.CONTENT_URI } // Now create and return a CursorLoader that will take care of // creating a Cursor for the data being displayed. val select: String = "((${Contacts.DISPLAY_NAME} NOTNULL) AND (" + "${Contacts.HAS_PHONE_NUMBER}=1) AND (" + "${Contacts.DISPLAY_NAME} != ''))" return (activity as? Context)?.let { context -> CursorLoader( context, baseUri, CONTACTS_SUMMARY_PROJECTION, select, null, "${Contacts.DISPLAY_NAME} COLLATE LOCALIZED ASC" ) } ?: throw Exception("Activity cannot be null") } override fun onLoadFinished(loader: Loader<Cursor>, data: Cursor) { // Swap the new cursor in. (The framework will take care of closing the // old cursor once we return.) mAdapter.swapCursor(data) } override fun onLoaderReset(loader: Loader<Cursor>) { // 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) } }
Java
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 curFilter; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Prepare the loader. Either re-connect with an existing one, // or start a new one. getLoaderManager().initLoader(0, null, this); } @Override public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { super.onViewCreated(view, 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); } @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. curFilter = !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 (curFilter != null) { baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, Uri.encode(curFilter)); } 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); } }
Ví dụ khác
Các ví dụ sau đây minh hoạ cách sử dụng trình tải:
- LoaderCursor: phiên bản hoàn chỉnh của đoạn mã trước đó.
- Truy xuất danh sách người liên hệ:
hướng dẫn sử dụng
CursorLoader
để truy xuất dữ liệu của nhà cung cấp danh bạ. - LoaderThrottle: ví dụ về cách sử dụng tính năng điều tiết để giảm số lượng của các truy vấn mà trình cung cấp nội dung thực hiện khi dữ liệu của trình cung cấp đó thay đổi.