Ladeprogramme

Mit Android 9 (API-Level 28) wurden Ladeprogramme eingestellt. Die empfohlene Option für das Laden von Daten beim Verarbeiten der Lebenszyklen Activity und Fragment ist die Verwendung eines Kombination aus ViewModel-Objekten und LiveData. Ansichtsmodelle überdauern Konfigurationsänderungen wie Ladeprogrammen, aber mit weniger Boilerplate-Code. LiveData bietet eine Lebenszyklus-orientierte Methode zum Laden von Daten, die Sie wiederverwenden können in mehrere Ansichtsmodelle nutzen. Sie können auch LiveData kombinieren mit MediatorLiveData Alle beobachtbaren Abfragen, z. B. von einem Raumdatenbank: Kann zur Beobachtung von Änderungen verwendet werden zu den Daten hinzufügen.

ViewModel und LiveData sind auch verfügbar, wenn du keinen Zugriff hast an den LoaderManager, z. B. in einem Service Wenn Sie die beiden in tandem ermöglicht den einfachen Zugriff auf die Daten, die Ihre App benötigt, ohne sich mit der Benutzeroberfläche befassen zu müssen Lebenszyklus. Weitere Informationen zu LiveData findest du in der Übersicht zu LiveData. Weitere Informationen über ViewModel finden Sie in der Übersicht zu ViewModel.

Mit der Loader API können Sie Daten aus einer Contentanbieter oder eine andere Datenquelle zur Anzeige in einem FragmentActivity oder Fragment.

Ohne Ladeprogramm können unter anderem folgende Probleme auftreten:

  • Wenn Sie die Daten direkt in der Aktivität oder im Fragment abrufen, reagieren nicht schnell, weil sie potenziell langsam sind. Abfragen aus dem UI-Thread.
  • Wenn Sie die Daten aus einem anderen Thread abrufen, z. B. mit AsyncTask, sind Sie für die Verwaltung beider Threads zuständig, und den UI-Thread durch verschiedene Aktivitäten oder Lebenszyklusereignisse von Fragmenten, wie onDestroy() und Konfigurationsänderungen.

Loader lösen diese Probleme und bieten weitere Vorteile:

  • Loader werden in separaten Threads ausgeführt, um eine langsame oder nicht reagierende Benutzeroberfläche zu verhindern.
  • Loader vereinfachen die Thread-Verwaltung, indem sie Callback-Methoden bereitstellen, wenn Ereignisse auftreten.
  • Loader bleiben bestehen und speichern Ergebnisse über Konfigurationsänderungen hinweg, um zu verhindern, doppelte Abfragen.
  • Loader können einen Beobachter implementieren, um Änderungen in der zugrunde liegenden Datenquelle verwendet werden. Beispielsweise wird CursorLoader automatisch registriert ein ContentObserver, um eine Aktualisierung auszulösen. wenn sich Daten ändern.

Loader API – Zusammenfassung

Es gibt mehrere Klassen und Benutzeroberflächen, die bei der Verwendung von Loader in einer App ein. Sie sind in der folgenden Tabelle zusammengefasst:

Klasse/Schnittstelle Beschreibung
LoaderManager Eine abstrakte Klasse, die mit einem FragmentActivity- oder Fragment für die Verwaltung von mindestens einem Loader Instanzen. Es gibt nur eine LoaderManager pro Aktivität oder Fragment, aber ein LoaderManager kann mehrere Loader verwalten.

Wenn du ein LoaderManager erhalten möchtest, ruf getSupportLoaderManager() an aus der Aktivität oder dem Fragment.

Um mit dem Laden von Daten aus einem Ladeprogramm zu beginnen, rufen Sie entweder initLoader() oder restartLoader(). Das System bestimmt automatisch, ob ein Loader mit der gleichen Ganzzahl-ID bereits vorhanden ist und entweder einen neuen Loader erstellt oder einen vorhandenen Loader wiederverwendet.

LoaderManager.LoaderCallbacks Diese Schnittstelle enthält Callback-Methoden, die aufgerufen werden, wenn loader-Ereignisse auftreten. Die -Schnittstelle definiert drei Callback-Methoden: <ph type="x-smartling-placeholder">
    </ph>
  • onCreateLoader(int, Bundle): wird aufgerufen, wenn das System einen neuen Loader benötigt. In Ihrem Code ein Loader-Objekt zu erstellen und es an System.
  • onLoadFinished(Loader<D>, D): wird aufgerufen, wenn ein Loader die Daten vollständig geladen hat. Normalerweise um dem Nutzer die Daten in Ihrem Code anzuzeigen.
  • onLoaderReset(Loader<D>): aufgerufen, wenn ein zuvor erstellter Loader zurückgesetzt wird, wenn Sie Folgendes aufrufen: destroyLoader(int) oder wenn die Aktivität oder das Fragment zerstört wird, wodurch seine Daten nicht mehr verfügbar sind. In Ihrem Code Entfernen Sie alle Verweise auf die Daten des Loaders.
Diese Schnittstelle wird in der Regel von Ihrer Aktivität oder Ihrem Fragment implementiert. registriert, wenn Sie initLoader() oder restartLoader()
Loader Loader laden Daten. Diese Klasse ist abstrakt und dient als Basisklasse für alle Loader. Sie können direkt abgeleitete Klassen erstellen, Loader oder eine der folgenden integrierten Funktionen verwenden abgeleiteten Klassen, um die Implementierung zu vereinfachen: <ph type="x-smartling-placeholder">

In den folgenden Abschnitten erfahren Sie, wie Sie diese Klassen und Schnittstellen in einer Anwendung.

Loader in einer Anwendung verwenden

In diesem Abschnitt wird beschrieben, wie Loader in einer Android-App verwendet werden. Eine -Anwendung, die Loader verwendet, enthält in der Regel Folgendes:

Ladeprogramm starten

Der LoaderManager verwaltet eine oder mehrere Loader-Instanzen innerhalb einer FragmentActivity oder Fragment. Es gibt nur eine LoaderManager pro Aktivität oder Fragment.

Normalerweise eine Loader in der onCreate()-Methode der Aktivität oder im onCreate()-Methode. Ich Gehen Sie dazu wie folgt 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() nimmt folgende Parameter:

  • Eine eindeutige ID, die den Loader identifiziert. In diesem Beispiel lautet die ID 0.
  • Optionale Argumente, die an den Loader übergeben werden sollen Konstruktion (in diesem Beispiel null).
  • Eine LoaderManager.LoaderCallbacks-Implementierung, die Die LoaderManager-Aufrufe zum Melden von Ladeereignissen. In dieser Beispiel: Die lokale Klasse implementiert die Schnittstelle LoaderManager.LoaderCallbacks und übergibt dann einen Verweis für sich selbst, this.

Der initLoader()-Aufruf sorgt dafür, dass ein Loader initialisiert und aktiv ist. Dies hat zwei mögliche Ergebnisse:

  • Wenn der durch die ID angegebene Loader bereits vorhanden ist, wird der zuletzt erstellte Loader wiederverwendet werden.
  • Wenn der durch die ID angegebene Loader nicht vorhanden ist, initLoader() löst die LoaderManager.LoaderCallbacks-Methode onCreateLoader(). Hier implementieren Sie den Code zum Instanziieren und Zurückgeben eines neuen Loaders. Weitere Informationen finden Sie im Abschnitt zu onCreateLoader.

In beiden Fällen wird die angegebene LoaderManager.LoaderCallbacks -Implementierung ist dem Loader zugeordnet und wird aufgerufen, wenn der Loader-Status ändert. Wenn sich der Anrufer zum Zeitpunkt des Anrufs im gestartet. Der angeforderte Loader ist bereits vorhanden und hat seinen dann ruft das System onLoadFinished() auf. sofort, im initLoader(). Dafür müssen Sie vorbereitet sein. Weitere Informationen zu diesem Callback finden Sie im Abschnitt über . onLoadFinished

Die Methode initLoader() gibt den erstellten Loader zurück. Sie brauchen aber keinen Verweis darauf zu erfassen. Der LoaderManager verwaltet automatisch die Lebensdauer des Ladeprogramms. Das LoaderManager startet und beendet den Ladevorgang bei Bedarf und behält den Ladezustand bei und die zugehörigen Inhalte.

Daher interagieren Sie selten mit Ladeprogrammen. . Meistens verwendest du die LoaderManager.LoaderCallbacks-Methoden, um in den Ladevorgang einzugreifen wenn bestimmte Ereignisse eintreten. Weitere Informationen zu diesem Thema finden Sie im Abschnitt LoaderManager-Rückrufe verwenden.

Ladeprogramm neu starten

Wenn Sie initLoader() verwenden, im vorherigen Abschnitt gezeigt wird, wird ein vorhandener Loader mit der angegebenen ID verwendet, sofern vorhanden. Ist dies nicht der Fall, wird eine erstellt. Manchmal möchten Sie jedoch Ihre alten Daten und fangen von vorne an.

Wenn Sie Ihre alten Daten verwerfen möchten, verwenden Sie restartLoader(). Beispiel: Implementierung von SearchView.OnQueryTextListener-Neustarts wenn sich die Abfrage des Nutzers ändert. Der Loader muss neu gestartet werden, dass er den überarbeiteten Suchfilter für eine neue Abfrage verwenden 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-Oberfläche. über die ein Client mit der LoaderManager interagieren kann.

Loader, insbesondere CursorLoader, ihre Daten nach dem Beenden behalten. Dadurch können Anwendungen ihre Daten aus den onStop()- und onStart()-Methoden der Aktivität oder des Fragments, sodass Wenn Nutzende zu einer Anwendung zurückkehren, müssen sie nicht warten, bis die Daten neu laden.

Mit den LoaderManager.LoaderCallbacks-Methoden ermitteln Sie, wann ein neuer Loader erstellt werden muss, und teilen der Anwendung mit, die Daten eines Loaders nicht mehr zu verwenden.

LoaderManager.LoaderCallbacks enthält diese Methoden:

  • onLoadFinished(): wird aufgerufen, wenn ein zuvor erstellter Loader das Laden beendet hat.
  • onLoaderReset(): wird aufgerufen, wenn ein zuvor erstellter Loader zurückgesetzt wird. Daten nicht verfügbar.

Diese Methoden werden in den folgenden Abschnitten ausführlicher beschrieben.

onCreateLoader

Wenn Sie versuchen, auf einen Loader zuzugreifen, z. B. über initLoader(), wird geprüft, der durch die ID angegebene Ladeprogramm existiert. Ist dies nicht der Fall, wird die LoaderManager.LoaderCallbacks-Methode onCreateLoader() ausgelöst. Dieses erstellen Sie einen neuen Loader. In der Regel ist dies eine CursorLoader, aber Sie können auch Ihre eigene Loader-Unterklasse implementieren.

Im folgenden Beispiel wird der onCreateLoader() -Callback-Methode ein CursorLoader-Element mithilfe der Konstruktormethode erstellt, benötigt alle Informationen, die zum Ausführen einer Abfrage an ContentProvider erforderlich sind. Insbesondere ist Folgendes erforderlich:

  • uri: Der URI für den abzurufenden Inhalt.
  • Projektion: Eine Liste der zurückzugebenden Spalten. Bestanden null gibt alle Spalten zurück, was ineffizient ist.
  • selection: ein Filter, der angibt, welche Zeilen zurückgegeben werden sollen als SQL-WHERE-Klausel formatiert (ohne das WHERE selbst). Bestanden null gibt alle Zeilen für den angegebenen URI zurück.
  • selectionArgs: Wenn Sie „?s“ in der Auswahl verwenden, werden sie werden durch die Werte aus selectionArgs in der Reihenfolge ersetzt, in der sie in ausgewählt haben. Die Werte sind als Strings gebunden.
  • sortOrder: Reihenfolge der als SQL formatierten Zeilen ORDER BY-Klausel (ohne ORDER BY selbst). Bestanden: null verwendet die Standardsortierreihenfolge, die möglicherweise ungeordnet 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 (OnLoadAbgeschlossen)

Diese Methode wird aufgerufen, wenn ein zuvor erstellter Loader das Laden beendet. Diese Methode wird garantiert vor der Freigabe der letzten Daten aufgerufen. der für diesen Loader bereitgestellt wird. Entfernen Sie an dieser Stelle jegliche Verwendung von da sie veröffentlicht werden. Geben Sie die Daten aber nicht weiter. der Loader gehört und sich darum kümmert.

Das Ladeprogramm gibt die Daten frei, sobald es weiß, dass die Anwendung nicht mehr verwenden. Wenn die Daten beispielsweise ein Cursor von einem CursorLoader sind, Rufen Sie close() nicht selbst auf. Wenn sich der Cursor in einer CursorAdapter platziert haben, verwenden Sie die Methode swapCursor(), damit der Die alte Cursor ist nicht geschlossen, 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);
}

onLoaderZurücksetzen

Diese Methode wird aufgerufen, wenn ein zuvor erstellter Loader zurückgesetzt wird. wodurch die Daten nicht mehr verfügbar sind. Mit diesem Callback können Sie herausfinden, wann die Daten veröffentlicht werden, damit Sie Ihren Verweis darauf entfernen können.

Diese Implementierung ruft swapCursor() mit einem Wert von 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);
}

Beispiel

Als Beispiel ist hier die vollständige Implementierung eines Fragment-Elements, bei dem ein ListView-Element angezeigt wird, das die Ergebnisse einer Abfrage beim Contentanbieter für Kontakte. Die Abfrage beim Anbieter wird mit einem CursorLoader verwaltet.

Da dieses Beispiel aus einer Anwendung für den Zugriff auf die Kontakte eines Nutzers stammt, ist es Manifest muss die Berechtigung enthalten, 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);
    }
}

Weitere Beispiele

Die folgenden Beispiele veranschaulichen die Verwendung von Ladeprogrammen:

  • <ph type="x-smartling-placeholder"></ph> LoaderCursor: Eine vollständige Version des vorherigen Snippets.
  • Kontaktliste abrufen: Schritt-für-Schritt-Anleitung, in der ein CursorLoader zum Abrufen Daten vom Kontaktanbieter
  • <ph type="x-smartling-placeholder"></ph> LoaderThrottle: Ein Beispiel für die Verwendung von Drosselung, um die Zahl zu reduzieren. von Abfragen, die ein Contentanbieter durchführt, wenn sich seine Daten ändern.