2014-01-21 5 views
12

LoaderManager hat diese Methode restartLoader():Führt LoaderManager.restartLoader() immer zu einem Aufruf von onCreateLoader()?

public abstract Loader<D> restartLoader (int id, Bundle args, LoaderCallbacks<D> callback)

Startet eine neue oder neu startet einen vorhandenen Loader in diesem Manager registriert die Rückrufe zu ihm, und (wenn die Aktivität/Fragment wird zur Zeit gestartet) beginnt es zu laden. Wenn ein Loader mit derselben ID zuvor gestartet wurde, wird er automatisch zerstört, wenn der neue Loader seine Arbeit beendet hat. Der Rückruf wird geliefert, bevor der alte Lader zerstört wird.

Basierend auf the dev guide, erhalte ich die Idee, dass in der Tat, ein Aufruf an onCreateLoader immer von restartLoader() führen:

Neustarten eines Loader

...

zu verwerfen Ihre alte Daten verwenden Sie restartLoader(). Diese Implementierung von SearchView.OnQueryTextListener startet beispielsweise den Loader neu, wenn sich die Abfrage des Benutzers ändert. Der Lader muss neu gestartet werden, damit es die überarbeiteten Suchfilter verwenden kann, um eine neue Abfrage zu tun:

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. 
    mCurFilter = !TextUtils.isEmpty(newText) ? newText : null; 
    getLoaderManager().restartLoader(0, null, this); 
    return true; 
} 

public Loader<Cursor> onCreateLoader(int id, Bundle args) { 
    // NOTE: The Loader is instantiated with the user's query 

    Uri baseUri;  
    if (mCurFilter != null) { 
     baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, 
        Uri.encode(mCurFilter)); 
    } 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"); 
} 

Im Beispiel onCreateLoader ist der einzige Ort, wo Informationen über die Anfrage des Benutzers an den Loader übergeben werden (auf Instantiierung). Aber die Dokumente werfen mich ab, indem sie sagen: Startet eine neue oder startet einen vorhandenen Loader neu.

Antwort

24

Die einfache Antwort auf Ihre Frage ist ja, ein Aufruf von restartLoader() wird onCreateLoader() erneut aufrufen.

Sie können mehr als ein Lader parallel starten (sagen Sie zwei SimpleCursorAdapters zu füllen), zB:

getLoaderManager().initLoader(0, null, this); //id = 0 
getLoaderManager().initLoader(1, null, this); //id = 1 

onCreateLoader dann vom Loader-Manager für jede ID genannt wird (der Loader, der zurückgegeben wird, ist dann asynchron vom Loader Manager) gebaut:

public Loader<Cursor> onCreateLoader(int id, Bundle args) 
{ 
    if (id == 0) 
     //return a Loader<Cursor> for id 0 
    else if (id == 1) 
     //return a Loader<Cursor> for id 1 
} 

der Loader Manager übergibt die resultierenden Lader onLoadFinished:

public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) 
{ 
    if (loader.getId() == 0) 
     //cursor was returned from onCreateLoader for id 0 
     //perhaps do swapCursor(cursor) on an adapter using this loader 
    else if (loader.getId() == 1) 
     //cursor was returned from onCreateLoader for id 1 
     //perhaps do swapCursor(cursor) on an adapter using this loader 
} 

Wenn Sie anschließend Neustart Loader aufrufen:

getLoaderManager().restartLoader(0, null, this); //id = 0 

... onLoaderReset zuerst genannt wird:

public void onLoaderReset(Loader<Cursor> loader) 
{ 
    if (loader.getId() == 0) 
     //perhaps do swapCursor(null) on an adapter using this loader 
    else if (loader.getId() == 1) 
     //perhaps do swapCursor(null) on an adapter using this loader 
} 

... durch einen neuen Anruf onCreateLoader gefolgt. Insofern wird onCreateLoader sowohl zum Starten eines brandneuen Loaders als auch zum Zurücksetzen eines vorhandenen Loaders verwendet.

+0

Ich denke, OnCreateLoader wird auch auf dem UI-Thread aufgerufen ...! – Maarten

+0

Ich bin interessiert, warum Sie denken, dass das der Fall ist? Das ist der Sinn von Loadern, asynchron mit einem ContentProvider/Datenquelle zu interagieren.Die lange laufende Aufgabe, die sonst die Benutzeroberfläche blockieren könnte, wird in onCreateLoader ausgeführt - der LoaderManager führt diesen Teil im Hintergrund aus. – NigelK

+0

Ja, ja, der ['loadInBackBackground'] (https://developer.android.com/reference/android/content/AsyncTaskLoader.html) Teil eines AsyncTaskLoader läuft sicher auf einem Hintergrundthread, aber ich denke onCreateLoader ist auf dem UI-Thread: [Clients von Loadern sollten in der Regel alle Aufrufe an einen Loader aus dem Hauptthread ihres Prozesses ausführen (dh der Thread, in dem die Aktivitätsrückrufe und andere Dinge auftreten).] (Https://developer.android .com/reference/android/content/Loader.html) - Vergleichbar mit der Instantiierung einer 'AsyncTask', das war meine Argumentation. – Maarten

Verwandte Themen