2017-07-06 6 views
2

Ich habe einige Fragmente in einem ViewPager geladen, wo jede "Seite" aus einer Zeile in einem Cursor geladen wird. Jedes Fragment zeigt ein Bild (JPEG) auf dem Gerät. Wenn der Benutzer das Fragment ablehnt (d. H. Swipe/Seitenwechsel, Hits back/up oder einfach die App ganz schließt), möchte ich eine Methode aufrufen, die die JPEG-Datei zum Schreiben öffnet und eine Aktualisierung ihrer Metadaten vornimmt. Die eigentliche Arbeit wird schließlich von der Apache Commons Imaging-Bibliothek übernommen.Funktioniert Fragment onStop auf UI-Thread

Ich habe dies implementiert, indem ich meine saveToFile() Methode aus jedem Lebenszyklus des Fragments onStop() Handler aufgerufen. Bedeutet dies, dass die gesamte Dateioperation auf dem UI-Thread ausgeführt wird? Sollte ich dafür unbedingt eine AsyncTask einrichten?

Sagen Sie die Datei schreiben aus irgendeinem Grund plötzlich (für einige JPEG) sollte eine lange Zeit dauern, zB 2 Minuten. Was würde dann passieren? Würde die UI auf diese Seite/dieses Fragment warten (einfrieren), bevor sie fortgesetzt wird? Oder würde der Prozess (in Datei schreiben) irgendwie "im Hintergrund" weiterlaufen? Oder würde der Prozess einfach umgebracht, kurzzeitig gestoppt?

Die Art, wie ich dies derzeit verdrahtet habe (onStop Aufruf saveToFile(), die die Bildgebungsbibliothek aufruft und dann die Datei aktualisiert) scheint zu funktionieren, wie es sollte. Selbst wenn ich die App beende, sehe ich immer noch meinen Toast-Text, der sagt: "In Datei schreiben ..." Scheinbar ist der Prozess nie gestört, und ich kann nicht sagen, dass ich irgendeine UI-Verzögerung erhalte.

+0

Ja, alle Lifecycle-Methoden von Activity & Fragment werden im Hauptthread ausgeführt (auch als UI-Thread bezeichnet). Sie können dies durch die Tatsache bestätigen, dass Sie mit Views in diesen Methoden spielen können. – Sufian

Antwort

2

onStop() - Handler. Bedeutet dies, dass die gesamte Dateioperation auf dem UI-Thread ausgeführt wird? Sollte ich definitiv eine AsyncTask für dies einrichten?

YES

Ein AsyncTask hat mehrere Teile: doInBackground eine Methode, die in der Tat der Fall ist, auf einem separaten Thread und das onPostExecute Verfahren ausführen, das auf dem UI-Thread ausgeführt wird.

Sie können auch eine Art Beobachtermuster wie EventBus verwenden, um Async auszuführen und Ergebnisse auf der Benutzeroberfläche zu veröffentlichen.


Sagen Sie die Datei schreiben aus irgendeinem Grund plötzlich (für einige jpeg) sollte eine lange Zeit in Anspruch nehmen, zB 2 Minuten. Was würde dann passieren? Würde die UI warten nur (freeze)

Die Anwendung stürzt ab, weil Android wird es zwangsweise schließen aufgrund ANR (Application reagiert nicht).

finden Sie in der offiziellen Dokumentation Einzelheiten hierzu: https://developer.android.com/training/articles/perf-anr.html

Android-Anwendungen normalerweise von Standard des „UI-Thread“ oder „Haupt-Thread“) vollständig auf einem einzigen Thread ausgeführt werden. Das bedeutet, alles, was Ihre Anwendung in dem UI-Thread macht, der eine lange Zeit dauert, bis kann den ANR-Dialog auslösen, weil Ihre Anwendung nicht eine Chance ist, die Eingabe Ereignis oder Absicht Broadcasts zu behandeln.

Daher sollte jede Methode, die im UI-Thread ausgeführt wird, so wenig wie möglich funktionieren auf diesem Thread. Insbesondere sollten Aktivitäten so wenig wie möglich in Schlüssel-Lebenszyklus-Methoden wie onCreate() und onResume() eingerichtet werden. Potenziell lang laufende Operationen wie Netzwerk- oder Datenbankoperationen oder rechenintensive Berechnungen wie die Größenanpassung von Bitmaps sollten in einem Worker -Thread (oder im Fall von Datenbankoperationen über eine asynchrone -Anforderung) ausgeführt werden.

Die effektivste Möglichkeit zum Erstellen eines Worker-Threads für längere Operationen ist mit der AsyncTask-Klasse.

Hier ist, was ich aber empfehle. Verwenden Sie den oben genannten EventBus und erstellen Sie eine BaseActivity, die automatisch die Daten für Sie speichert onClose() durch Auslösen eines Ereignisses, das Async ausführt. Sie erweitern diese Basisaktivität dann an allen Stellen, an denen Sie Autosave-Funktionen benötigen.

Hier ist was ich meine mit einem Beispiel, das EventBus verwendet.

public abstract class BaseActivity extends Activity{ 

@Override 
protected void onResume(){ 
    if(!EventBus.getDefault().isRegistered(this)) 
     EventBus.getDefault().register(this); 
    super.onResume(); 
} 

@Override 
protected void onDestroy() { 
    if(EventBus.getDefault().isRegistered(this)) 
    EventBus.getDefault().unregister(this); 
    super.onDestroy(); 
} 

@Override 
protected void onStop() { 
    super.onStop(); 
    //We fire event and pass the current parent class that inherited this base. 
    EventBus.getDefault().post(new EventBusProcessMySaveData(this.getClass())); 
} 
} 

//Your model class to use with EventBus 
public final class EventBusProcessMySaveData{ 
    private final Class className; 

    public EventBusProcessMySaveData(final Class className){ 
     this.className = className; 
    } 

    public Class getClassName(){ 
     return this.className; 
    } 
} 


public class MyMainActivity extends BaseActivity{ 
    //Do you standard setup here onCreate() and such... 

    //Handle Event for Saving Operation, async. 
    //This will fire everytime theres an onClose() IN ANY activity that 
    //extends BaseActivity, but will only process if the class names match. 
    @Subscribe(threadMode = ThreadMode.ASYNC) 
    public void methodNameDoesNotReallyMatterHere(final EventBusProcessMySaveData model){ 
     //We make sure this is the intended receiving end by comparing current class name 
     //with received class name. 
     if(model.getClassName().equals(this.getClass())){ 
      //Do whatever you need to do that's CPUintensive here. 
     } 
    } 

} 
+0

Richtig, danke. Eine AsyncTask wird jedoch als eine Klasse beschrieben, mit der "lang andauernde Aufgaben ausgeführt werden, die zu Aktualisierungen der GUI führen." In meinem Fall möchte ich nur die Datei im Hintergrund aktualisieren, nachdem der Benutzer tatsächlich mit der Benutzeroberfläche fertig ist. Wenn die Task keine Änderung in der Benutzeroberfläche verursacht, sollte ich dann noch AsyncTask oder einen anderen "Worker-Thread" verwenden? – joakimk

+0

"Wenn die Aufgabe keine Änderung in der Benutzeroberfläche erzeugt, sollte ich dann noch AsyncTask oder vielleicht einen anderen" Worker-Thread "verwenden?" - Wenn Sie nicht mit der Benutzeroberfläche sprechen müssen, starten Sie einfach einen neuen Hintergrund-Thread oder ein Worker-Thread. Weitere Informationen finden Sie in der Dokumentation - https://developer.android.com/guide/components/processes-and-threads.html – Dayan

+0

Ja, nochmals vielen Dank! Das klingt nach dem, was ich brauche. – joakimk