Unterschied zwischen initLoader und restartLoader in LoaderManager

129

Ich bin völlig verloren in Bezug auf die Unterschiede zwischen den initLoaderund den restartLoaderFunktionen der LoaderManager:

  • Sie haben beide die gleiche Unterschrift.
  • restartLoader Erstellt auch einen Loader, falls dieser nicht vorhanden ist ("Startet einen neuen oder startet einen vorhandenen Loader in diesem Manager neu").

Gibt es eine Beziehung zwischen den beiden Methoden? Ruft der Anruf restartLoaderimmer an initLoader? Kann ich anrufen, restartLoaderohne anrufen zu müssen initLoader? Ist es sicher, initLoaderzweimal anzurufen , um die Daten zu aktualisieren? Wann sollte ich eine der beiden verwenden und warum ?

theomega
quelle

Antworten:

202

Um diese Frage zu beantworten, müssen Sie sich in den LoaderManagerCode vertiefen. Während die Dokumentation für LoaderManager selbst nicht klar genug ist (oder es würde diese Frage nicht geben), ist die Dokumentation für LoaderManagerImpl, eine Unterklasse des abstrakten LoaderManager, viel aufschlussreicher.

initLoader

Rufen Sie an, um eine bestimmte ID mit einem Loader zu initialisieren. Wenn dieser ID bereits ein Loader zugeordnet ist, bleibt sie unverändert, und alle vorherigen Rückrufe werden durch die neu bereitgestellten ersetzt. Wenn derzeit kein Loader für die ID vorhanden ist, wird ein neuer erstellt und gestartet.

Diese Funktion sollte im Allgemeinen beim Initialisieren einer Komponente verwendet werden, um sicherzustellen, dass ein Loader erstellt wird, auf den sie sich verlässt. Auf diese Weise können vorhandene Daten eines Loaders wiederverwendet werden, sofern bereits eine vorhanden ist. Wenn beispielsweise eine Aktivität nach einer Konfigurationsänderung neu erstellt wird, müssen die Loader nicht neu erstellt werden.

restartLoader

Rufen Sie an, um den einer bestimmten ID zugeordneten Loader neu zu erstellen. Wenn dieser ID derzeit ein Loader zugeordnet ist, wird dieser entsprechend abgebrochen / gestoppt / zerstört. Ein neuer Loader mit den angegebenen Argumenten wird erstellt und seine Daten werden Ihnen zugestellt, sobald sie verfügbar sind.

[...] Nach dem Aufruf dieser Funktion werden alle vorherigen Loader, die dieser ID zugeordnet sind, als ungültig betrachtet, und Sie erhalten keine weiteren Datenaktualisierungen von ihnen.

Grundsätzlich gibt es zwei Fälle:

  1. Der Loader mit der ID existiert nicht: Beide Methoden erstellen einen neuen Loader, sodass dort kein Unterschied besteht
  2. Der Loader mit der ID ist bereits vorhanden: initLoaderErsetzt nur die als Parameter übergebenen Rückrufe, bricht den Loader jedoch nicht ab oder stoppt ihn nicht. Für a CursorLoaderbedeutet dies, dass der Cursor offen und aktiv bleibt (falls dies vor dem initLoaderAufruf der Fall war ). `restartLoader hingegen bricht den Loader ab, stoppt und zerstört ihn (und schließt die zugrunde liegende Datenquelle wie einen Cursor) und erstellt einen neuen Loader (der auch einen neuen Cursor erstellen und die Abfrage erneut ausführen würde, wenn der Loader dies ist ein CursorLoader).

Hier ist der vereinfachte Code für beide Methoden:

initLoader

LoaderInfo info = mLoaders.get(id);
if (info == null) {
    // Loader doesn't already exist -> create new one
    info = createAndInstallLoader(id, args, LoaderManager.LoaderCallbacks<Object>)callback);
} else {
   // Loader exists -> only replace callbacks   
   info.mCallbacks = (LoaderManager.LoaderCallbacks<Object>)callback;
}

restartLoader

LoaderInfo info = mLoaders.get(id);
if (info != null) {
    LoaderInfo inactive = mInactiveLoaders.get(id);
    if (inactive != null) {
        // does a lot of stuff to deal with already inactive loaders
    } else {
        // Keep track of the previous instance of this loader so we can destroy
        // it when the new one completes.
        info.mLoader.abandon();
        mInactiveLoaders.put(id, info);
    }
}
info = createAndInstallLoader(id, args,  (LoaderManager.LoaderCallbacks<Object>)callback);

Wie wir sehen können, erstellen beide Methoden einen neuen Loader (info = createAndInstallLoader (...)), falls der Loader nicht vorhanden ist (info == null). Falls der Loader bereits vorhanden ist, werden initLoadernur die Rückrufe (info.mCallbacks = ...) ersetzt, während restartLoaderder alte Loader inaktiviert wird (er wird zerstört, wenn der neue Loader seine Arbeit beendet) und anschließend ein neuer erstellt.

Somit ist jetzt klar, wann initLoaderund wann zu verwenden ist restartLoaderund warum es sinnvoll ist, die beiden Methoden zu verwenden. initLoaderwird verwendet, um sicherzustellen, dass ein initialisierter Loader vorhanden ist. Wenn keine vorhanden ist, wird eine neue erstellt. Wenn eine bereits vorhanden ist, wird sie wiederverwendet. Wir verwenden diese Methode immer, es sei denn, wir benötigen einen neuen Loader, da sich die auszuführende Abfrage geändert hat (nicht die zugrunde liegenden Daten, sondern die tatsächliche Abfrage wie in der SQL-Anweisung für einen CursorLoader). In diesem Fall rufen wir auf restartLoader.

Der Aktivitäts- / Fragment-Lebenszyklus hat nichts mit der Entscheidung zu tun, die eine oder andere Methode zu verwenden (und es ist nicht erforderlich, die Anrufe mithilfe eines One-Shot-Flags zu verfolgen, wie von Simon vorgeschlagen)! Diese Entscheidung wird ausschließlich aufgrund der "Notwendigkeit" eines neuen Laders getroffen. Wenn wir dieselbe Abfrage ausführen möchten, die wir verwenden initLoader, wenn wir eine andere Abfrage ausführen möchten, die wir verwenden restartLoader.

Wir könnten immer verwenden, restartLoaderaber das wäre ineffizient. Nach einer Bildschirmrotation oder wenn der Benutzer von der App weg navigiert und später zu derselben Aktivität zurückkehrt, möchten wir normalerweise dasselbe Abfrageergebnis anzeigen. Daher restartLoaderwürde der Loader unnötig neu erstellt und das zugrunde liegende (möglicherweise teure) Abfrageergebnis verworfen.

Es ist sehr wichtig, den Unterschied zwischen den geladenen Daten und der "Abfrage" zum Laden dieser Daten zu verstehen. Nehmen wir an, wir verwenden einen CursorLoader, der eine Tabelle nach Bestellungen abfragt. Wenn dieser Tabelle eine neue Reihenfolge hinzugefügt wird, verwendet der CursorLoader onContentChanged (), um die Benutzeroberfläche zu informieren, die neue Reihenfolge zu aktualisieren und anzuzeigen ( restartLoaderin diesem Fall nicht erforderlich ). Wenn wir nur offene Aufträge anzeigen möchten, benötigen wir eine neue Abfrage und restartLoadergeben einen neuen CursorLoader zurück, der die neue Abfrage widerspiegelt.


Gibt es eine Beziehung zwischen den beiden Methoden?

Sie teilen den Code, um einen neuen Loader zu erstellen, aber sie tun verschiedene Dinge, wenn bereits ein Loader vorhanden ist.

Ruft der Anruf restartLoaderimmer an initLoader?

Nein, das tut es nie.

Kann ich anrufen, restartLoaderohne anrufen zu müssen initLoader?

Ja.

Ist es sicher, initLoaderzweimal anzurufen , um die Daten zu aktualisieren?

Es ist sicher, initLoaderzweimal anzurufen, aber es werden keine Daten aktualisiert.

Wann sollte ich eine der beiden verwenden und warum ?


Das sollte (hoffentlich) nach meinen obigen Erklärungen klar sein.

Konfigurationsänderungen

Ein LoaderManager behält seinen Status bei Konfigurationsänderungen (einschließlich Orientierungsänderungen) bei, sodass Sie denken, dass wir nichts mehr zu tun haben. Denk nochmal...

Erstens behält ein LoaderManager die Rückrufe nicht bei. Wenn Sie also nichts tun, erhalten Sie keine Anrufe zu Ihren Rückrufmethoden wie onLoadFinished()und dergleichen, und das wird Ihre App sehr wahrscheinlich beschädigen.

Daher MÜSSEN wir zumindest aufrufen initLoader, um die Rückrufmethoden wiederherzustellen (a restartLoaderist natürlich auch möglich). In der Dokumentation heißt es:

Befindet sich der Anrufer zum Zeitpunkt des Anrufs im Startzustand und der angeforderte Loader existiert bereits und hat seine Daten generiert, wird der Rückruf onLoadFinished(Loader, D)sofort (innerhalb dieser Funktion) aufgerufen [...].

Das heißt, wenn wir initLoadernach einer Orientierungsänderung anrufen , erhalten wir sofort einen onLoadFinishedAnruf, da die Daten bereits geladen sind (vorausgesetzt, dies war vor der Änderung der Fall). Das klingt zwar einfach, kann aber schwierig sein (lieben wir nicht alle Android ...).

Wir müssen zwischen zwei Fällen unterscheiden:

  1. Behandelt die Konfigurationsänderungen selbst: Dies ist der Fall für Fragmente, die setRetainInstance (true) verwenden, oder für eine Aktivität mit dem entsprechenden android:configChangesTag im Manifest. Diese Komponenten erhalten nach einer Bildschirmdrehung keinen onCreate-Aufruf. Denken Sie also daran, eine initLoader/restartLoaderandere Rückrufmethode (z onActivityCreated(Bundle). B. in ) aufzurufen . Um die Loader initialisieren zu können, müssen die Loader-IDs gespeichert werden (z. B. in einer Liste). Da die Komponente bei Konfigurationsänderungen beibehalten wird, können wir einfach die vorhandenen Loader-IDs durchlaufen und aufrufen initLoader(loaderid, ...).
  2. Verarbeitet Konfigurationsänderungen nicht selbst: In diesem Fall können die Loader in onCreate initialisiert werden, aber wir müssen die Loader-IDs manuell beibehalten, sonst können wir die erforderlichen initLoader / restartLoader-Aufrufe nicht ausführen. Wenn die IDs in einer ArrayList gespeichert sind, führen wir einen
    outState.putIntegerArrayList(loaderIdsKey, loaderIdsArray)in onSaveInstanceState durch und stellen die IDs in onCreate: wieder her, loaderIdsArray = savedInstanceState.getIntegerArrayList(loaderIdsKey)bevor wir die initLoader-Aufrufe ausführen.
Emanuel Moecklin
quelle
: +1: Ein letzter Punkt. Wenn Sie initLoadernach einer Rotation verwenden (und alle Rückrufe beendet sind, ist Loader inaktiv), erhalten Sie keinen onLoadFinishedRückruf, aber wenn Sie verwenden, werden restartLoaderSie?
Blundell
Falsch. Die initLoader-Methode ruft die onLoadFinished () -Methode auf, bevor sie zurückgegeben wird (wenn der Loader gestartet ist und Daten enthält). Ich habe einen Absatz über Konfigurationsänderungen hinzugefügt, um dies genauer zu erläutern.
Emanuel Moecklin
6
Ah, natürlich ergibt eine Kombination aus Ihrer Antwort und @ alexlockwoods das vollständige Bild. Ich denke, die Antwort für andere ist, verwenden Sie initLoader, wenn Ihre Abfrage statisch ist, und restartLoader, wenn Sie die Abfrage ändern möchten
Blundell
1
Das ruft es schön auf: "Verwenden Sie initLoader, wenn Ihre Abfrage statisch ist, und restartLoader, wenn Sie die Abfrage ändern möchten"
Emanuel Moecklin
1
@Mhd. Tahawi, Sie ändern die Rückrufe nicht, sondern setzen sie nur dort, wo sie hingehen sollen. Nach einer Bildschirmrotation müssen sie zurückgesetzt werden, da Android sie nicht in der Nähe hält, um Speicherverluste zu vermeiden. Sie können sie auf alles einstellen, was Sie wollen, solange sie das Richtige tun.
Emanuel Moecklin
46

Der Aufruf , initLoaderwenn der Loader bereits erstellt wurde (dies geschieht in der Regel nach Konfigurationsänderungen, zum Beispiel) erzählt die LoaderManager des Loader der jüngsten Daten zu liefern onLoadFinishedsofort. Wenn der Loader noch nicht erstellt wurde (z. B. beim ersten Start der Aktivität / des Fragments), initLoaderweist der Aufruf an den LoaderManager onCreateLoaderan, den neuen Loader zu erstellen.

Das Aufrufen restartLoaderzerstört einen bereits vorhandenen Loader (sowie alle damit verbundenen vorhandenen Daten) und weist den LoaderManager an, aufzurufen onCreateLoader, um den neuen Loader zu erstellen und einen neuen Load zu initiieren.


Auch hier ist die Dokumentation ziemlich klar:

  • initLoaderstellt sicher, dass ein Loader initialisiert und aktiv ist. Wenn der Loader noch nicht vorhanden ist, wird einer erstellt und (wenn die Aktivität / das Fragment gerade gestartet wird) der Loader gestartet. Andernfalls wird der zuletzt erstellte Loader wiederverwendet.

  • restartLoaderStartet einen neuen Loader oder startet einen vorhandenen Loader in diesem Manager neu, registriert die Rückrufe und lädt ihn (wenn die Aktivität / das Fragment gerade gestartet wird). Wenn ein Lader mit derselben ID zuvor gestartet wurde, wird er automatisch zerstört, wenn der neue Lader seine Arbeit beendet hat. Der Rückruf wird zugestellt, bevor der alte Lader zerstört wird.

Alex Lockwood
quelle
@TomanMoney Ich habe in meiner Antwort erklärt, was es bedeutet. Über welchen Teil bist du verwirrt?
Alex Lockwood
Sie haben gerade den Doc aufgewärmt. Das Dokument gibt jedoch keinen Hinweis darauf, wo die einzelnen Methoden angewendet werden sollten und warum es schlecht ist, sie durcheinander zu bringen. Nach meiner Erfahrung funktioniert es einwandfrei, nur restartLoader aufzurufen und niemals initLoader aufzurufen. Das ist also immer noch verwirrend.
Tom anMoney
3
@TomanMoney Normalerweise verwenden Sie initLoader()in onCreate()/, onActivityCreated()wenn die Aktivität / das Fragment zum ersten Mal gestartet wird. Auf diese Weise wird beim ersten Öffnen einer Aktivität durch den Benutzer der Loader zum ersten Mal erstellt. Bei nachfolgenden Konfigurationsänderungen, bei denen die gesamte Aktivität / das gesamte Fragment zerstört werden muss, wird beim folgenden Aufruf von initLoader()einfach die alte Loaderstatt zurückgegeben ein neues erstellen. Normalerweise verwenden Sie diese Option, restartLoader()wenn Sie die LoaderAbfrage des Benutzers ändern müssen (dh wenn Sie gefilterte / sortierte Daten usw. erhalten möchten).
Alex Lockwood
4
Ich bin immer noch verwirrt über die API-Entscheidung, beide Methoden zu verwenden, da sie dieselbe Signatur haben. Warum konnte die API keine einzelne startLoader () -Methode sein, die jedes Mal das "Richtige" tut? Ich denke, das ist der Teil, der viele Leute verwirrt.
Tom anMoney
1
@TomanMoney In der Dokumentation hier heißt es: developer.android.com/guide/components/loaders.html . "Sie verbinden sich automatisch wieder mit dem Cursor des letzten Laders, wenn sie nach einer Konfigurationsänderung neu erstellt werden. Daher müssen sie ihre Daten nicht erneut abfragen."
Igor Ganapolsky
16

Ich bin kürzlich auf ein Problem mit mehreren Loader-Managern und Änderungen der Bildschirmausrichtung gestoßen und möchte sagen, dass nach vielen Versuchen und Irrtümern das folgende Muster sowohl für Aktivitäten als auch für Fragmente für mich funktioniert:

onCreate: call initLoader(s)
          set a one-shot flag
onResume: call restartLoader (or later, as applicable) if the one-shot is not set.
          unset the one-shot in either case.

(mit anderen Worten, setzen einige Flagge , so dass initLoader wird immer ausgeführt , sobald & dass restartLoader ist auf der Flucht 2. und nachfolgenden Durchgängen durch onResume )

Denken Sie auch daran, jedem Ihrer Lader innerhalb einer Aktivität unterschiedliche IDs zuzuweisen (was bei Fragmenten innerhalb dieser Aktivität ein Problem sein kann, wenn Sie mit Ihrer Nummerierung nicht vorsichtig sind).


Ich habe versucht, nur initLoader zu verwenden ... schien nicht effektiv zu funktionieren.

Versucht initLoader auf onCreate mit null Argumenten (Dokumente sagen, dass dies in Ordnung ist) & restartLoader (mit gültigen Argumenten) in onResume .... Dokumente sind falsch & initLoader löst eine Nullzeiger-Ausnahme aus.

Versucht restartLoader nur ... funktioniert für eine Weile, bläst aber auf 5. oder 6. Bildschirm Neuausrichtung.

Versuchte initLoader in onResume ; funktioniert wieder eine Weile und bläst dann. (speziell der Fehler "DoRetain aufgerufen, wenn nicht gestartet:" ...)

Versuchte Folgendes: (Auszug aus einer Cover-Klasse, deren Loader-ID an den Konstruktor übergeben wurde)

/**
 * start or restart the loader (why bother with 2 separate functions ?) (now I know why)
 * 
 * @param manager
 * @param args
 * @deprecated use {@link #restart(LoaderManager, Bundle)} in onResume (as appropriate) and {@link #initialise(LoaderManager, Bundle)} in onCreate 
 */
@Deprecated 
public void start(LoaderManager manager, Bundle args) {
    if (manager.getLoader(this.id) == null) {
        manager.initLoader(this.id, args, this);
    } else {
        manager.restartLoader(this.id, args, this);
    }
}

(was ich irgendwo in Stack-Overflow gefunden habe)

Wieder funktionierte dies für eine Weile, warf aber immer noch gelegentlich einen Fehler.


Nach dem, was ich beim Debuggen herausfinden kann, hat meiner Meinung nach etwas mit dem Speichern / Wiederherstellen des Instanzstatus zu tun, das erfordert, dass initLoader (s) im onCreate- Teil des Lebenszyklus ausgeführt werden, um einen Spin des Zyklus zu überstehen . ( Ich kann mich irren.)

Bei Managern, die erst gestartet werden können, wenn die Ergebnisse von einem anderen Manager oder einer anderen Aufgabe stammen (dh nicht in onCreate initialisiert werden können ), verwende ich nur initLoader . (Ich bin möglicherweise nicht korrekt, aber es scheint zu funktionieren. Diese sekundären Loader sind nicht Teil des unmittelbaren Instanzstatus, sodass die Verwendung von initLoader in diesem Fall möglicherweise tatsächlich korrekt ist.)

Lebenszyklus


Wenn ich mir die Diagramme und Dokumente anschaue, hätte ich gedacht, dass initLoader in onCreate & restartLoader in onRestart for Activities verwendet werden sollte, aber Fragmente mit einem anderen Muster verbleiben, und ich hatte keine Zeit zu untersuchen, ob dies tatsächlich stabil ist. Kann jemand anderes kommentieren, ob er mit diesem Muster für Aktivitäten Erfolg hat?

Simon
quelle
/ @ Simon ist 100% korrekt und dies sollte die akzeptierte Antwort sein. Ich glaubte seiner Antwort nicht ganz und verbrachte mehrere Stunden damit, verschiedene Wege zu finden, um diese Arbeit zu machen. Sobald ich den initLoader-Aufruf auf onCreate verschoben hatte, funktionierten die Dinge. Sie benötigen dann das One-Shot-Flag, um die Zeiten zu berücksichtigen, zu denen onStart aufgerufen wird, aber kein onCreate
CjS
2
"Nur restartLoader versucht ... funktioniert eine Weile, bläst aber bei der Neuausrichtung des 5. oder 6. Bildschirms." Es tut? Ich habe es einfach versucht und den Bildschirm hundertmal gedreht und keine Explosion bekommen. Was für eine Ausnahme bekommen Sie?
Tom anMoney
-1 Ich schätze den Forschungsaufwand hinter dieser Antwort, aber die meisten Ergebnisse sind falsch.
Emanuel Moecklin
1
@IgorGanapolsky fast alles. Wenn Sie meine Antwort lesen und verstehen, werden Sie verstehen, was initLoader und restartLoader tun und wann Sie welche verwenden müssen, und Sie werden auch verstehen, warum fast alle Schlussfolgerungen von Simon falsch sind. Es gibt keinen Zusammenhang zwischen dem Lebenszyklus eines Fragments / einer Aktivität und der Entscheidung, wann initLoader / restartLoader verwendet werden soll (mit einer Einschränkung, die ich unter Konfigurationsänderungen erläutere). Simon schließt aus Versuch und Irrtum, dass der Lebenszyklus der Schlüssel zum Verständnis der beiden Methoden ist, aber nicht.
Emanuel Moecklin
@IgorGanapolsky Ich versuche nicht, meine eigene Antwort zu bewerben. Ich versuche lediglich, anderen Entwicklern zu helfen und sie daran zu hindern, Simons Ergebnisse für ihre eigenen Apps zu verwenden. Sobald Sie verstanden haben, wofür die beiden Methoden gedacht sind, wird das Ganze ziemlich offensichtlich und einfach zu implementieren.
Emanuel Moecklin
0

initLoaderverwendet dieselben Parameter erneut, wenn der Loader bereits vorhanden ist. Es wird sofort zurückgegeben, wenn alte Daten bereits geladen sind, auch wenn Sie sie mit neuen Parametern aufrufen. Der Lader sollte idealerweise automatisch die Aktivität neuer Daten benachrichtigen. Wenn sich der Bildschirm dreht, wird er initLoadererneut aufgerufen und die alten Daten werden sofort angezeigt.

restartLoaderDies ist der Fall, wenn Sie ein erneutes Laden erzwingen und auch die Parameter ändern möchten. Wenn Sie mit Ladern einen Anmeldebildschirm erstellen, rufen Sie nur restartLoaderjedes Mal auf, wenn Sie auf die Schaltfläche klicken. (Die Schaltfläche kann aufgrund falscher Anmeldeinformationen usw. mehrmals angeklickt werden.) Sie würden nur dann anrufen, initLoaderwenn der gespeicherte Instanzstatus der Aktivität wiederhergestellt wird, wenn der Bildschirm während einer Anmeldung gedreht wurde.

Monstieur
quelle
-1

Wenn der Loader bereits vorhanden ist, stoppt / storniert / zerstört restartLoader den alten, während initLoader ihn nur mit dem angegebenen Rückruf initialisiert. Ich kann nicht herausfinden, was die alten Rückrufe in diesen Fällen bewirken, aber ich denke, sie werden einfach aufgegeben.

Ich habe http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.0.1_r1/android/app/LoaderManager.java gescannt , kann aber nicht herausfinden, was genau ist Unterschied ist, abgesehen davon, dass die Methoden verschiedene Dinge tun. Ich würde also sagen, benutze initLoader das erste Mal und starte für die folgenden Male neu, obwohl ich nicht mit Sicherheit sagen kann, was jeder von ihnen genau tun wird.

koljaTM
quelle
Und was wird initLoaderin diesem Fall tun?
Theomega
-1

Der Init Loader verwendet beim ersten Start die Methode loadInBackground (), beim zweiten Start wird sie weggelassen. Meiner Meinung nach ist die bessere Lösung:

Loader<?> loa; 
try {
    loa = getLoaderManager().getLoader(0);
} catch (Exception e) {
    loa = null;
}
if (loa == null) {
    getLoaderManager().initLoader(0, null, this);
} else {
    loa.forceLoad();
}

////////////////////////////////////////////////////////// ///////////////////////////////

protected SimpleCursorAdapter mAdapter;

private abstract class SimpleCursorAdapterLoader 
    extends AsyncTaskLoader <Cursor> {

    public SimpleCursorAdapterLoader(Context context) {
        super(context);
    }

    @Override
    protected void onStartLoading() {
        if (takeContentChanged() || mAdapter.isEmpty()) {
            forceLoad();
        }
    }

    @Override
    protected void onStopLoading() {
        cancelLoad();
    }

    @Override
    protected void onReset() {
        super.onReset();
        onStopLoading();
    }
}

Ich habe viel Zeit damit verbracht, diese Lösung zu finden - restartLoader (...) hat in meinem Fall nicht richtig funktioniert. Mit dem einzigen forceLoad () können Sie den vorherigen Ladethread ohne Rückruf beenden (damit alle DB-Transaktionen ordnungsgemäß abgeschlossen werden) und einen neuen Thread erneut starten. Ja, es erfordert etwas mehr Zeit, ist aber stabiler. Nur der zuletzt gestartete Thread wird zurückgerufen. Wenn Sie also Tests mit Unterbrechung Ihrer Datenbanktransaktionen durchführen möchten - versuchen Sie es mit Willkommen, versuchen Sie, Loader (...) neu zu starten, andernfalls forceLoad (). Der einzige Vorteil von restartLoader (...) besteht darin, neue Anfangsdaten zu liefern, ich meine Parameter. Und bitte vergessen Sie in diesem Fall nicht, den Loader in der onDetach () -Methode des geeigneten Fragments zu zerstören. Denken Sie auch daran, dass manchmal, wenn Sie eine Aktivität haben und, sagen sie, 2 Fragmente mit jeweils einem Loader einschließlich Aktivität - Sie erreichen nur 2 Loader-Manager. Daher teilt Activity seinen LoaderManager mit Fragmenten, die beim Laden zuerst auf dem Bildschirm angezeigt werden. Versuchen Sie LoaderManager.enableDebugLogging (true); um die Details in jedem bestimmten Fall zu sehen.

user1700099
quelle
2
-1 zum Umschließen des Anrufs getLoader(0)in a try { ... } catch (Exception e) { ... }.
Alex Lockwood