Seit Android 9 (API-Level 28) werden Loader nicht mehr unterstützt. Wenn Sie sich mit dem Laden von Daten bei der Verarbeitung der Lebenszyklen Activity
und Fragment
befassen möchten, empfehlen wir, eine Kombination aus ViewModel
-Objekten und LiveData
zu verwenden.
Sie können Modelle auch nach Konfigurationsänderungen wie Loadern, jedoch mit weniger Boilerplate-Code ansehen. LiveData
bietet eine lebenszyklusbasierte Methode zum Laden von Daten, die Sie in Modellen für mehrere Ansichten wiederverwenden können. Sie können LiveData
auch mit MediatorLiveData
kombinieren.
Mit allen beobachtbaren Abfragen, z. B. aus einer Raumdatenbank, können Änderungen an den Daten beobachtet werden.
ViewModel
und LiveData
sind auch in Situationen verfügbar, in denen du keinen Zugriff auf LoaderManager
hast, z. B. in Service
. Die Kombination aus beiden bietet eine einfache Möglichkeit, auf die Daten zuzugreifen, die Ihre App benötigt, ohne sich mit dem UI-Lebenszyklus befassen zu müssen. Weitere Informationen zu LiveData
finden Sie in der Übersicht zu LiveData
. Weitere Informationen zu ViewModel
finden Sie in der Übersicht zu ViewModel
.
Mit der Loader API können Sie Daten aus einem Contentanbieter oder einer anderen Datenquelle zur Anzeige in einem FragmentActivity
- oder Fragment
-Objekt laden.
Ohne Loader können unter anderem folgende Probleme auftreten:
- Wenn Sie die Daten direkt in der Aktivität oder dem Fragment abrufen, reagieren Ihre Nutzer möglicherweise nicht richtig, da sie möglicherweise langsame Abfragen über den UI-Thread ausführen.
- Wenn Sie die Daten aus einem anderen Thread abrufen, z. B. mit
AsyncTask
, sind Sie dafür verantwortlich, sowohl diesen Thread als auch den UI-Thread über verschiedene Aktivitäts- oder Fragment-Lebenszyklusereignisse wieonDestroy()
und Konfigurationsänderungen zu verwalten.
Loader lösen diese Probleme und bieten weitere Vorteile:
- Loader werden in separaten Threads ausgeführt, um eine langsame oder nicht reagierende UI zu verhindern.
- Loader vereinfachen die Thread-Verwaltung, indem sie beim Eintreten von Ereignissen Callback-Methoden bereitstellen.
- Loader bleiben erhalten und speichern die Ergebnisse über Konfigurationsänderungen hinweg im Cache, um doppelte Abfragen zu vermeiden.
- Loader können einen Beobachter implementieren, der Änderungen an der zugrunde liegenden Datenquelle überwacht. Beispielsweise registriert
CursorLoader
automatisch einenContentObserver
, um eine Aktualisierung auszulösen, wenn sich Daten ändert.
Zusammenfassung der Loader API
Bei der Verwendung von Ladeprogrammen in einer Anwendung können mehrere Klassen und Schnittstellen beteiligt sein. Sie sind in der folgenden Tabelle zusammengefasst:
Klasse/Benutzeroberfläche | Beschreibung |
---|---|
LoaderManager |
Eine abstrakte Klasse, die einem FragmentActivity oder Fragment zum Verwalten einer oder mehrerer Loader -Instanzen zugeordnet ist. Es gibt nur eine LoaderManager pro Aktivität oder Fragment, aber eine LoaderManager kann mehrere Loader verwalten.
Um ein Rufen Sie entweder |
LoaderManager.LoaderCallbacks |
Diese Schnittstelle enthält Callback-Methoden, die aufgerufen werden, wenn Loader-Ereignisse auftreten. In der Schnittstelle sind drei Callback-Methoden definiert:
initLoader() oder restartLoader() aufrufen.
|
Loader |
Loader führen das Laden der Daten durch. Diese Klasse ist abstrakt und dient als Basisklasse für alle Loader. Sie können Loader direkt abgeleitet haben oder eine der folgenden integrierten abgeleiteten Klassen verwenden, um die Implementierung zu vereinfachen:
|
In den folgenden Abschnitten erfahren Sie, wie Sie diese Klassen und Schnittstellen in einer Anwendung verwenden.
Loader in einer Anwendung verwenden
In diesem Abschnitt wird die Verwendung von Loadern in einer Android-Anwendung beschrieben. Eine Anwendung, die Loader verwendet, umfasst in der Regel Folgendes:
- Ein
FragmentActivity
oderFragment
. - Eine Instanz von
LoaderManager
. - Ein
CursorLoader
zum Laden von Daten, die von einemContentProvider
gestützt werden. Alternativ können Sie Ihre eigene abgeleitete Klasse vonLoader
oderAsyncTaskLoader
implementieren, um Daten aus einer anderen Quelle zu laden. - Eine Implementierung für
LoaderManager.LoaderCallbacks
. Hier erstellen Sie neue Loader und verwalten Ihre Verweise auf vorhandene Ladeprogramme. - Eine Möglichkeit, die Daten des Ladeprogramms anzuzeigen, z. B.
SimpleCursorAdapter
. - Eine Datenquelle wie
ContentProvider
bei Verwendung vonCursorLoader
.
Ladeprogramm starten
Der LoaderManager
verwaltet eine oder mehrere Loader
-Instanzen innerhalb von FragmentActivity
oder Fragment
. Es gibt nur ein LoaderManager
pro Aktivität oder Fragment.
In der Regel initialisieren Sie Loader
in der Methode onCreate()
der Aktivität oder in der Methode onCreate()
des Fragments. Gehen Sie dazu so vor:
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);
Die Methode initLoader()
verwendet die folgenden Parameter:
- Eine eindeutige ID, die das Ladeprogramm identifiziert. In diesem Beispiel lautet die ID
0
. - Optionale Argumente, die beim Erstellen an das Ladeprogramm übergeben werden sollen (in diesem Beispiel
null
). - Eine
LoaderManager.LoaderCallbacks
-Implementierung, die vonLoaderManager
aufgerufen wird, um Ladeereignisse zu melden. In diesem Beispiel implementiert die lokale Klasse dieLoaderManager.LoaderCallbacks
-Schnittstelle und übergibt einen Verweis aufthis
.
Der Aufruf initLoader()
sorgt dafür, dass ein Ladeprogramm initialisiert und aktiv wird. Dies hat zwei mögliche Ergebnisse:
- Wenn das mit der ID angegebene Ladeprogramm bereits vorhanden ist, wird das zuletzt erstellte Ladeprogramm wiederverwendet.
- Wenn das durch die ID angegebene Ladeprogramm nicht vorhanden ist, löst
initLoader()
dieLoaderManager.LoaderCallbacks
-MethodeonCreateLoader()
aus. Hier implementieren Sie den Code, um einen neuen Loader zu instanziieren und zurückzugeben. Weitere Informationen finden Sie im Abschnitt zuonCreateLoader
.
In beiden Fällen ist die angegebene LoaderManager.LoaderCallbacks
-Implementierung mit dem Ladeprogramm verknüpft und wird aufgerufen, wenn sich der Status des Ladeprogramms ändert. Wenn sich der Aufrufer zum Zeitpunkt dieses Aufrufs im Status „Gestartet“ befindet, das angeforderte Ladeprogramm bereits vorhanden ist und seine Daten generiert hat, ruft das System onLoadFinished()
sofort während initLoader()
auf. Sie müssen darauf vorbereitet sein. Weitere Informationen zu diesem Callback finden Sie im Abschnitt zu
onLoadFinished
.
Die Methode initLoader()
gibt den erstellten Loader
zurück, Sie müssen jedoch keinen Verweis darauf erfassen. LoaderManager
verwaltet die Lebensdauer des Ladeprogramms automatisch. Der LoaderManager
startet und beendet den Ladevorgang bei Bedarf und behält den Status des Ladeprogramms und des zugehörigen Inhalts bei.
Wie das impliziert, werden Sie selten direkt mit den Loadern interagieren.
Sie verwenden am häufigsten die Methoden LoaderManager.LoaderCallbacks
, um in den Ladeprozess einzugreifen, wenn bestimmte Ereignisse auftreten. Weitere Informationen zu diesem Thema findest du im Abschnitt LoaderManager-Rückrufe verwenden.
Ladeprogramm neu starten
Wenn Sie initLoader()
wie im vorherigen Abschnitt gezeigt verwenden, wird ein vorhandenes Ladeprogramm mit der angegebenen ID verwendet, sofern vorhanden.
Falls nicht, wird eins erstellt. Aber manchmal möchten Sie Ihre alten
Daten verwerfen und von vorne beginnen.
Wenn Sie Ihre alten Daten verwerfen möchten, verwenden Sie restartLoader()
. Mit der folgenden Implementierung von SearchView.OnQueryTextListener
wird beispielsweise das Ladeprogramm neu gestartet, wenn sich die Abfrage des Nutzers ändert. Das Ladeprogramm muss neu gestartet werden, damit es mit dem überarbeiteten Suchfilter eine neue Abfrage ausführen kann.
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; }
LoaderManager-Callbacks verwenden
LoaderManager.LoaderCallbacks
ist eine Callback-Schnittstelle, über die ein Client mit der LoaderManager
interagieren kann.
Von Loadern, insbesondere CursorLoader
, wird erwartet, dass ihre Daten nach dem Beenden beibehalten werden. So behalten Anwendungen ihre Daten über die onStop()
- und onStart()
-Methoden der Aktivität oder des Fragments, sodass Nutzer nicht warten müssen, bis die Daten neu geladen wurden, wenn sie zu einer Anwendung zurückkehren.
Mit den Methoden LoaderManager.LoaderCallbacks
können Sie feststellen, wann ein neues Ladeprogramm erstellt werden soll, und der Anwendung mitteilen, wann die Verwendung der Daten eines Ladeprogramms beendet werden soll.
LoaderManager.LoaderCallbacks
enthält diese Methoden:
onCreateLoader()
: instanziiert und gibt eine neueLoader
für die angegebene ID zurück.
-
onLoadFinished()
: Wird aufgerufen, wenn ein zuvor erstelltes Ladeprogramm das Laden abgeschlossen hat.
onLoaderReset()
: Wird aufgerufen, wenn ein zuvor erstelltes Ladeprogramm zurückgesetzt wird, wodurch seine Daten nicht mehr verfügbar sind.
Diese Methoden werden in den folgenden Abschnitten ausführlicher beschrieben.
onCreateLoader
Wenn Sie versuchen, z. B. über initLoader()
auf ein Ladeprogramm zuzugreifen, wird geprüft, ob das durch die ID angegebene Ladeprogramm vorhanden ist. Andernfalls wird die LoaderManager.LoaderCallbacks
-Methode onCreateLoader()
ausgelöst. Hier erstellen Sie ein neues Ladeprogramm. In der Regel ist dies eine CursorLoader
, Sie können jedoch auch Ihre eigene abgeleitete Loader
-Klasse implementieren.
Im folgenden Beispiel erstellt die Callback-Methode onCreateLoader()
ein CursorLoader
mithilfe ihrer Konstruktormethode, die alle erforderlichen Informationen zum Ausführen einer Abfrage an ContentProvider
benötigt. Insbesondere benötigt sie Folgendes:
- uri: URI für den abzurufenden Inhalt
- Projektion: Eine Liste der zurückzugebenden Spalten. Bei Übergabe von
null
werden alle Spalten zurückgegeben. Dies ist ineffizient. - selection: Ein Filter, der angibt, welche Zeilen zurückgegeben werden sollen, im Format einer SQL-WHERE-Klausel (ohne WHERE selbst). Bei Übergabe von
null
werden alle Zeilen für den angegebenen URI zurückgegeben. - selectionArgs: Wenn Sie ?s in der Auswahl angeben, werden diese in der Reihenfolge durch die Werte aus selectionArgs ersetzt, in der sie in der Auswahl vorkommen. Die Werte sind als Zeichenfolgen gebunden.
- sortOrder: Damit werden die als SQL-ORDER BY-Klausel formatierten Zeilen (mit Ausnahme der ORDER BY selbst) sortiert. Bei Übergabe von
null
wird die Standardsortierreihenfolge verwendet, die möglicherweise nicht geordnet ist.
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"); }
onLoadFinished
Diese Methode wird aufgerufen, wenn ein zuvor erstellter Loader den Ladevorgang abgeschlossen hat. Diese Methode wird garantiert vor der Veröffentlichung der letzten für diesen Loader bereitgestellten Daten aufgerufen. An diesem Punkt sollten Sie jegliche Nutzung der alten Daten entfernen, da sie freigegeben werden. Geben Sie die Daten jedoch nicht selbst frei. Der Loader besitzt sie und kümmert sich darum.
Das Ladeprogramm gibt die Daten frei, sobald erkannt wird, dass die Anwendung sie nicht mehr verwendet. Wenn die Daten beispielsweise ein Cursor von einem CursorLoader
sind, rufen Sie dafür nicht selbst close()
auf. Wenn der Cursor in einem CursorAdapter
platziert wird, verwenden Sie die Methode swapCursor()
, damit die alte Cursor
nicht geschlossen wird, wie im folgenden Beispiel gezeigt:
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
Diese Methode wird aufgerufen, wenn ein zuvor erstelltes Ladeprogramm zurückgesetzt wird, wodurch seine Daten nicht mehr verfügbar sind. Mit diesem Callback können Sie herausfinden, wann die Daten demnächst veröffentlicht werden, damit Sie Ihren Verweis darauf entfernen können.
Bei dieser Implementierung wird swapCursor()
mit dem Wert null
aufgerufen:
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); }
Beispiel
Im Folgenden sehen Sie als Beispiel die vollständige Implementierung eines Fragment
, der ein ListView
mit den Ergebnissen einer Abfrage an den Contentanbieter der Kontakte anzeigt. Sie verwendet ein CursorLoader
, um die Abfrage beim Anbieter zu verwalten.
Da dieses Beispiel aus einer Anwendung stammt, mit der auf die Kontakte eines Nutzers zugegriffen wird, muss das Manifest die Berechtigung READ_CONTACTS
enthalten.
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); } }
Weitere Beispiele
Die folgenden Beispiele veranschaulichen die Verwendung von Loadern:
- LoaderCursor: Eine vollständige Version des vorherigen Snippets.
- Kontaktliste abrufen: Schritt-für-Schritt-Anleitung, bei der mit einer
CursorLoader
Daten vom Kontaktanbieter abgerufen werden - LoaderThrottle: Ein Beispiel für die Verwendung der Drosselung, um die Anzahl der Abfragen zu reduzieren, die ein Contentanbieter bei Änderungen seiner Daten ausführt.