Ładowarki

Moduły ładujące zostały wycofane w Androidzie 9 (poziom interfejsu API 28). Zalecana opcja w przypadku do wczytywania danych przy obsłudze cykli życia Activity i Fragment jest użycie kombinacja obiektów ViewModel i LiveData. Wyświetlanie modeli przeżywa zmiany konfiguracji, takie jak moduły ładowania, ale prostsza metoda. LiveData umożliwia wczytywanie z uwzględnieniem cyklu życia danych, które można wykorzystać ponownie modeli wielu widoków. Możesz też połączyć LiveData za pomocą: MediatorLiveData Wszystkie obserwowalne zapytania, takie jak z bazy danych sal, która może służyć do obserwowania zmian; danych.

Usługi ViewModel i LiveData są też dostępne, gdy nie masz dostępu do LoaderManager, na przykład w Service. Zastosowanie dwóch tandem zapewnia prosty sposób dostępu do danych, których potrzebuje aplikacja, bez konieczności zajmowania się interfejsem użytkownika cyklu życia usługi. Więcej informacji o funkcji LiveData znajdziesz tutaj: LiveData omówienie. Aby dowiedzieć się więcej o: ViewModel, zobacz ViewModel przegląd.

Interfejs Loader API umożliwia wczytywanie danych z dostawca treści lub inne źródło danych do wyświetlenia w tabeli FragmentActivity lub Fragment.

Jeśli nie masz żadnych programów ładujących, mogą wystąpić m.in. te problemy:

  • Jeśli pobierzesz dane bezpośrednio w aktywności lub we fragmencie, użytkownicy mają brak reakcji z powodu potencjalnie powolnego działania z wątku interfejsu użytkownika.
  • Jeśli pobierasz dane z innego wątku, na przykład za pomocą funkcji AsyncTask, to Ty odpowiadasz za zarządzanie oraz z wątkiem UI za pomocą różnych zdarzeń cyklu życia działań lub fragmentów, takich jak onDestroy() i zmiany w konfiguracji.

Moduły wczytujące umożliwiają rozwiązanie tych problemów i zapewniają inne korzyści:

  • Moduły ładowania działają w osobnych wątkach, aby zapobiegać powolnym lub nieodpowiadającym działaniu interfejsu.
  • Moduły wczytujące upraszczają zarządzanie wątkami, udostępniając metody wywołania zwrotnego, gdy zdarzenia wystąpienia.
  • Moduły wczytywania są zachowywane i zapisywane w pamięci podręcznej po zmianie konfiguracji, co uniemożliwia podwójne zapytania.
  • Moduły wczytujące mogą wdrożyć obserwatora do monitorowania zmian w bazowym źródła danych. Na przykład: CursorLoader automatycznie rejestruje ContentObserver, aby uruchomić ponowne załadowanie gdy dane ulegną zmianie.

Podsumowanie interfejsu Loader API

Korzystanie z różnych klas i interfejsów programy ładujące w aplikacji. Ich podsumowanie znajdziesz w tej tabeli:

Klasa/interfejs Opis
LoaderManager Klasa abstrakcyjna powiązana z elementem FragmentActivity lub Fragment za zarządzanie co najmniej jednym Loader instancji. Jest tylko jedna LoaderManager za działanie lub fragment, ale LoaderManager może zarządzać wieloma modułami wczytującymi.

Aby otrzymać LoaderManager, zadzwoń pod numer getSupportLoaderManager() od aktywności lub fragmentu.

Aby zacząć ładować dane z programu wczytującego, wywołaj jedną initLoader() lub restartLoader() System automatycznie określa, czy moduł ładujący o takim samym identyfikatorze i tworzy nowy moduł ładowania lub używa istniejącego.

LoaderManager.LoaderCallbacks Ten interfejs zawiera metody wywołania zwrotnego, które są wywoływane, gdy zdarzenia ładowania. Interfejs definiuje 3 metody wywołania zwrotnego:
  • onCreateLoader(int, Bundle): gdy system potrzebuje nowego programu wczytującego. W kodzie utworzysz obiekt Loader i zwrócisz go w systemie.
  • onLoadFinished(Loader<D>, D): jest wywoływana, gdy moduł wczytywania zakończy wczytywanie danych. Zazwyczaj wyświetlanie danych użytkownikowi w kodzie.
  • onLoaderReset(Loader<D>): jest wywoływane, gdy utworzony wcześniej program ładujący jest resetowany, destroyLoader(int) lub gdy aktywność lub fragment kodu zostaje zniszczony, przez co jego dane są niedostępne. W kodzie usuń wszelkie odwołania do danych modułu wczytywania.
. Twoje działanie lub fragment zazwyczaj implementuje ten interfejs i jest to zarejestrowane podczas rozmowy initLoader() lub restartLoader()
Loader Moduły wczytujące dane wczytują dane. Ta klasa jest abstrakcyjna i służy jako klasę bazową wszystkich modułów ładowania. Możesz bezpośrednio podklasę Loader lub skorzystaj z jednego z poniższych podklasy, aby uprościć implementację:

W sekcjach poniżej dowiesz się, jak używać tych funkcji klas i interfejsów w aplikacji.

Korzystanie z programów wczytujących w aplikacji

W tej sekcji opisujemy, jak korzystać z programów uruchamiających w aplikacji na Androida. An to zwykle:

Uruchom program ładujący

LoaderManager zarządza co najmniej 1 wystąpieniem Loader w obrębie FragmentActivity lub Fragment Obowiązuje tylko 1 element LoaderManager na aktywność lub fragment.

Zazwyczaj zainicjuj element Loader w ramach metody onCreate() aktywności lub tagu onCreate(). Ty wykonaj te czynności:

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);

Metoda initLoader() pobiera następujące parametry:

  • Unikalny identyfikator identyfikujący program ładujący. W tym przykładzie identyfikator to 0.
  • Opcjonalne argumenty do przekazania do narzędzia ładującego na stronie konstrukcje (w tym przykładzie null).
  • Implementacja LoaderManager.LoaderCallbacks, która wywołania funkcji LoaderManager do raportowania zdarzeń wczytywania. W tym klasa lokalna implementuje interfejs LoaderManager.LoaderCallbacks, przekazuje więc odwołanie do siebie samej, this.

Wywołanie initLoader() zapewnia, że program wczytujący jest zainicjowany i aktywny. Może to wynikać z dwóch rezultatów:

  • Jeśli istnieje już moduł wczytujący określony przez identyfikator, ostatnio utworzony moduł wczytywania został użyty ponownie.
  • Jeśli moduł wczytujący określony przez identyfikator nie istnieje, initLoader() uruchamia LoaderManager.LoaderCallbacks metoda onCreateLoader(). Tutaj implementujesz kod, by utworzyć instancję i zwrócić nowy komponent wczytujący. Więcej dyskusji znajdziesz w sekcji na temat onCreateLoader.

W obu przypadkach LoaderManager.LoaderCallbacks jest powiązana z modułem wczytującym i jest wywoływana, gdy zmian stanu modułu wczytywania. Jeśli w trakcie tej rozmowy rozmówca jest w że żądany moduł ładujący już istnieje i wygenerował danych, system wywołuje funkcję onLoadFinished() natychmiast w ciągu initLoader(). Trzeba się na to przygotować. Więcej informacji o tym wywołaniu zwrotnym znajdziesz w sekcji onLoadFinished

Metoda initLoader() zwraca utworzoną Loader, ale nie trzeba tworzyć odwołania. Zarządzany przez: LoaderManager automatyczne wczytywanie. LoaderManager uruchamia się i zatrzymuje ładowanie w razie potrzeby oraz zachowuje stan modułu ładującego i powiązanych z nimi treści.

Jak to wskazuje, rzadko wchodzisz w interakcje z programami ładującymi. bezpośrednio. Najczęściej używasz metod LoaderManager.LoaderCallbacks do ingerencji w ładowanie gdy wystąpią określone zdarzenia. Więcej informacji na ten temat znajdziesz w sekcji Używanie wywołań zwrotnych narzędzia LoaderManager.

Ponowne uruchamianie programu wczytującego

Jeśli użyjesz metody initLoader(), jako pokazane w poprzedniej sekcji, wykorzystuje istniejący moduł ładowania o podanym identyfikatorze (jeśli taki istnieje). Jeśli go nie ma, zostanie utworzony. Czasem chcesz odrzucić stare dane i zacząć od nowa.

Aby odrzucić stare dane, użyj restartLoader(). Na przykład: wdrożenie SearchView.OnQueryTextListener ponownych uruchomień gdy zmieni się zapytanie użytkownika. Trzeba uruchomić ponownie program ładujący, że może użyć zmienionego filtra wyszukiwania do utworzenia nowego zapytania.

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;
}

Używanie wywołań zwrotnych narzędzia LoaderManager

LoaderManager.LoaderCallbacks to interfejs wywołania zwrotnego który pozwala klientowi na interakcję z LoaderManager.

Moduły wczytujące, a zwłaszcza CursorLoader, powinny zachowywania swoich danych po zatrzymaniu. Dzięki temu aplikacje mogą w ramach metod onStop() i onStart() aktywności lub fragmentu, aby gdy użytkownicy wracają do aplikacji, nie muszą czekać, aż dane zostaną załaduj ponownie.

Korzystasz z metod LoaderManager.LoaderCallbacks, aby wiedzieć, kiedy należy utworzyć nowy program ładujący, i powiadomić aplikację, kiedy czas, aby przestać używać danych programu wczytującego.

LoaderManager.LoaderCallbacks zawiera te metody:

  • onLoadFinished(): jest wywoływana, gdy utworzony wcześniej moduł wczytywania zakończy wczytywanie.
  • onLoaderReset(): gdy utworzony wcześniej moduł ładujący jest resetowany, przez co jego dane niedostępne.

Metody te zostały szczegółowo opisane w kolejnych sekcjach.

onCreateLoader

Gdy próbujesz uzyskać dostęp do programu wczytującego, na przykład za pomocą initLoader(), sprawdza on, istnieje program wczytujący określony przez ten identyfikator. Jeśli tak nie jest, aktywuje metodę LoaderManager.LoaderCallbacks onCreateLoader(). Ten tworzy się nowy moduł ładujący. Zwykle jest to CursorLoader, ale możesz wdrożyć własną podklasę Loader.

W poniższym przykładzie onCreateLoader() wywołania zwrotnego tworzy CursorLoader przy użyciu metody konstruktora, która wymaga pełnego zestawu informacji potrzebnych do wykonania zapytania do funkcji ContentProvider. Konkretnie chodzi o:

  • uri: identyfikator URI treści, która ma zostać pobrana.
  • odwzorowanie: lista kolumn do zwrócenia. Podania Funkcja null zwraca wszystkie kolumny, co jest nieefektywne.
  • wybór: filtr określający, które wiersze mają zostać zwrócone; sformatowana jako klauzula SQL WHERE (bez samej klauzuli WHERE). Podania Funkcja null zwraca wszystkie wiersze dla danego identyfikatora URI.
  • selectionArgs: jeśli w zaznaczonym miejscu dodasz znaki ?s, zostaną one usunięte są zastępowane wartościami z selectionArgs w kolejności, w jakiej występują w zaznaczania. Wartości są powiązane jako ciągi znaków.
  • sortOrder: kolejność wierszy w formacie SQL Klauzula ORDER BY (z wyłączeniem samego ORDER BY). Wyprzedza: null korzysta z domyślnej kolejności sortowania, która może nie być porządkowa.

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

Ta metoda jest wywoływana, gdy wcześniej utworzony program ładujący zakończy ładowanie. Gwarantujemy, że ta metoda zostanie wywołana przed opublikowaniem ostatnich danych który jest dostarczany dla tego programu wczytującego. Na tym etapie usuń wszelkie użycie niż te stare. Nie udostępniaj danych ładunek należy do Ciebie i zajmuje się tym.

Moduł ładowania udostępnia dane, gdy dowie się, że aplikacja nie jest już za jego pomocą. Jeśli na przykład dane są kursorem z elementu CursorLoader, nie dzwoń samodzielnie na numer close(). Jeśli kursor znajduje się w pozycji umieszczone w CursorAdapter, użyj metody swapCursor(), aby Stara architektura Cursor nie jest zamknięta, jak w tym przykładzie:

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

Ta metoda jest wywoływana podczas resetowania utworzonego wcześniej modułu ładującego, dlatego przez udostępnienie danych na jej temat. Dzięki temu wywołaniu możesz dowiedzieć się, kiedy dane są zostanie zwolniony, więc możesz usunąć swoje odnośniki.

Ta implementacja wymaga swapCursor() z wartością 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);
}

Przykład

Oto pełna implementacja elementu Fragment, który wyświetla element ListView zawierający wyników zapytania względem dostawcy treści kontaktów. Do zarządzania zapytaniem u dostawcy używa on interfejsu CursorLoader.

Ponieważ ten przykład pochodzi z aplikacji uzyskującej dostęp do kontaktów użytkownika, jej plik manifestu musi zawierać uprawnienia 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);
    }
}

Więcej przykładów

Poniższe przykłady pokazują, jak korzystać z programów wczytujących: