2015-03-28 12 views
30

Ich bin dabei, (endlich) das Kapitel über Aufgaben für mein Buch zu schreiben, und ich stoße auf ein paar lange Rätsel.Was sind die Unterschiede zwischen FLAG_ACTIVITY_RESET_TASK_IF_NEEDED und FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP?

Dinge, die als Home-Bildschirm Werfer dienen scheinen, um die Kombination von FLAG_ACTIVITY_NEW_TASK und FLAG_ACTIVITY_RESET_TASK_IF_NEEDED zu verwenden, wenn sie die angeforderte Launcher Aktivität starten:

Intent i=new Intent(Intent.ACTION_MAIN); 

i.addCategory(Intent.CATEGORY_LAUNCHER); 
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | 
      Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); 
i.setComponent(name); 

startActivity(i); 

The documentation for FLAG_ACTIVITY_RESET_TASK_IF_NEEDED hat:

Wenn gesetzt, und diese Aktivität Wird entweder in einer neuen Aufgabe gestartet oder eine vorhandene Aufgabe an die Spitze gebracht, dann wird sie als erste Tür der Aufgabe gestartet. Dies führt dazu, dass alle Affinitäten angewendet werden, die erforderlich sind, um diese Aufgabe in den richtigen Zustand zu bringen (indem entweder Aktivitäten zu oder von ihr verschoben werden) oder diese Aufgabe bei Bedarf einfach in ihren Anfangszustand zurückgesetzt wird.

Das ist nicht besonders klar.

Insbesondere scheint es, dass die gleichen Effekte unter Verwendung einer Kombination von FLAG_ACTIVITY_CLEAR_TOP und FLAG_ACTIVITY_SINGLE_TOP zu sehen wären. Zitiert die Dokumentation für FLAG_ACTIVITY_CLEAR_TOP:

Wenn gesetzt, und die Aktivität gestartet wird, ist bereits in der aktuellen Aufgabe ausgeführt wird, dann anstatt eine neue Instanz dieser Aktivität starten, alle anderen Aktivitäten auf der Spitze wird es sein, geschlossen und diese Absicht wird an die (jetzt oben) alte Aktivität als neue Absicht gesendet ...

Die aktuell ausgeführte Instanz von [die gewünschte Aktivität] erhält entweder die neue Absicht, die Sie hier starten, in ihrem onNewIntent() Methode, oder sei selbst beendet und mit der neuen Absicht neu gestartet. Wenn der Startmodus auf "multiple" (Standard) festgelegt wurde und Sie FLAG_ACTIVITY_SINGLE_TOP nicht in derselben Absicht festgelegt haben, wird er beendet und neu erstellt. Für alle anderen Startmodi oder wenn FLAG_ACTIVITY_SINGLE_TOP gesetzt ist, wird diese Absicht an onNewIntent() der aktuellen Instanz übergeben.

Die FLAG_ACTIVITY_CLEAR_TOP Dokumentation macht Sinn, zumindest für mich.

Also, was macht FLAG_ACTIVITY_RESET_TASK_IF_NEEDED das ist anders als die Kombination von FLAG_ACTIVITY_CLEAR_TOP und FLAG_ACTIVITY_SINGLE_TOP?


Bonuspunkte, wenn Sie erklären kann, was FLAG_ACTIVITY_CLEAR_TASK tut das aus einem der anderen beiden oben beschriebenen Optionen unterscheidet.

Wenn diese Eigenschaft in einem Intent an Context.startActivity() übergeben wird, bewirkt dieses Flag, dass vor dem Start der Aktivität alle vorhandenen Aufgaben gelöscht werden, die der Aktivität zugeordnet werden. Das heißt, die Aktivität wird zur neuen Wurzel einer ansonsten leeren Aufgabe, und alle alten Aktivitäten sind beendet. Dies kann nur in Verbindung mit FLAG_ACTIVITY_NEW_TASK verwendet werden.

Ein offensichtlicher Unterschied zwischen diesem und FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP ist das FLAG_ACTIVITY_CLEAR_TASK benötigt FLAG_ACTIVITY_NEW_TASK. Aber abgesehen davon scheint es, als wären die Nettoeffekte gleich und stimmen auch mit FLAG_ACTIVITY_RESET_TASK_IF_NEEDED überein.

+1

Ich erinnere mich, dass 'FLAG_ACTIVITY_RESET_TASK_IF_NEEDED' etwas Bestimmtes tun, wenn es mit' FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET' verwendet wird, aber anscheinend ist dieses Flag jetzt veraltet und seine Dokumentation ist verschwunden ([altes Dokument kann hier gefunden werden] (http://grepcode.com/file) /repository.grepcode.com/java/ext/com.google.android/android/2.3_r1/android/content/Intent.java#Intent.0FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET)). Es heißt jetzt, 'FLAG_ACTIVITY_NEW_DOCUMENT' zu verwenden, aber ich bin mir nicht sicher, ob es genau dasselbe tut. Das ist ein wenig verwirrend ... – Dalmas

+3

@Dalmas das ist nur eine Umbenennung. Wenn Sie sich den Code ansehen, wird NEW_DOCUMENT gleich CLEAR_WHEN_RESET gesetzt. Sie sind das Gleiche. –

Antwort

34

Ich habe mir den Quellcode für die ActivityManager angesehen. Die Flagge Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED macht in der Tat einige Magie, die Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP nicht tut: Es löst Task Reparieren.

Hier ist ein (wenn auch lame) Beispiel:

In App A wir die Wurzel Aktivität haben RootA und wir haben eine andere Aktivität ReparentableA:

<application 
     android:label="@string/app_name"> 
    <activity android:name=".RootA"> 
     <intent-filter> 
      <action android:name="android.intent.action.MAIN"/> 
      <category android:name="android.intent.category.LAUNCHER"/> 
     </intent-filter> 
    </activity> 
    <activity android:name=".ReparentableA" 
      android:allowTaskReparenting="true"/> 
</application> 

App A den Paketnamen „com.app hat. a "so ist der Standard taskAffinity seiner Komponenten" com.app.a ".

In App B haben wir die Wurzel Aktivität RootB:

<application 
     android:label="@string/app_name"> 
    <activity android:name="RootB"> 
     <intent-filter> 
      <action android:name="android.intent.action.MAIN"/> 
      <category android:name="android.intent.category.LAUNCHER"/> 
     </intent-filter> 
    </activity> 
</application> 

App B den Paketnamen "com.app.b" so der Standard-taskAffinity seiner Komponenten ist "com.app.b" hat.

Jetzt starten wir App B vom Startbildschirm aus. Dies startet eine neue Aufgabe und erstellt eine neue Instanz der Aktivität RootB als Stammaktivität in dieser Aufgabe. Die Aktivität RootB startet jetzt die Aktivität ReparentableA auf die übliche Weise, ohne spezielle Flags. Eine Instanz von ReparentableA wird erstellt und im aktuellen Task auf RootB gesetzt.

Drücken Sie auf STARTSEITE.

Jetzt starten wir App A vom Startbildschirm aus. Dies startet eine neue Aufgabe und erstellt eine neue Instanz der Aktivität RootA als Stammaktivität in dieser Aufgabe. HINWEIS: Wenn Android einen "Launcher" Intent startet, werden automatisch die Flags Intent.FLAG_ACTIVITY_NEW_TASK und Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED gesetzt. Aus diesem Grund löst das Starten von RootA jetzt das Reparieren von Aufgaben aus. Android prüft, ob es Aktivitäten in anderen Aufgaben gibt, die eine Affinität für diese neue Aufgabe haben (und sie sind reparierbar).Es findet ReparentableA (das die gleiche Aufgabenaffinität wie RootA hat) in der Aufgabe von App B und verschiebt es zu der neuen App A-Aufgabe. Wenn wir App A starten, sehen wir RootA nicht, wir sehen tatsächlich ReparentableA, da es an den Anfang der neuen Aufgabe verschoben wird.

Wenn wir zu App B zurückkehren, können wir sehen, dass ReparentableA aus dem Aufgabenstapel verschwunden ist und diese Aufgabe besteht jetzt aus nur einer Aktivität: RootB.


Hinweise zur Verwendung Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP

Die wichtige Sache über die Verwendung dieser Flags zu erinnern, „eine Aufgabe zurückgesetzt“ ist, dass es funktioniert nur, wenn bereits eine Instanz der Zielaktivität ist an der Wurzel die Aufgabe. Wenn Ihre Stammaktivität jemals beendet wird, können Sie Ihre Aufgabe nicht löschen, indem Sie die Stammaktivität mit Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP starten. Android erstellt einfach eine neue Instanz der Zielaktivität (root) und fügt sie zu den vorhandenen Aktivitäten in der Aufgabe hinzu, was wahrscheinlich nicht das ist, was Sie wollen.


Unterschied zwischen Intent.FLAG_ACTIVITY_CLEAR_TASK und Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP:

Wie oben erwähnt, mit CLEAR_TOP | SINGLE_TOP funktioniert nur, wenn es bereits eine Instanz der Zielaktivität in der Aufgabe. CLEAR_TASK entfernt jedoch alle Aktivitäten von der Aufgabe, unabhängig davon, ob eine Instanz der Zielaktivität in der Aufgabe vorhanden war oder nicht. Außerdem stellt die Verwendung von CLEAR_TASK sicher, dass die Zielaktivität zur Stammaktivität der Aufgabe wird, ohne dass Sie wissen müssen, welche Aktivität die Stammaktivität war, bevor Sie die Aufgabe gelöscht haben.


Unterschied zwischen Intent.FLAG_ACTIVITY_CLEAR_TASK und Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED:

Wie oben angegeben, mit CLEAR_TASK wird immer alle Aktivitäten von der Aufgabe entfernen und eine neue Instanz der Zielaktivität zu starten. Im Gegensatz dazu wird RESET_TASK_IF_NEEDED die Aufgabe nur in bestimmten Situationen zurücksetzen (der "IF_NEEDED" -Teil). Die Aufgabe wird nur „Reset“, wenn Android ist entweder:

  • eine neue Aufgabe erstellen (in diesem Fall die „Reset“ Funktionalität beinhaltet die Aufgabe Neuzuordnung oben erläutert), oder
  • Wenn Android ist eine Hintergrundaufgabe bringen in den Vordergrund (in diesem Fall wird die Aufgabe nur von Aktivitäten gelöscht, die mit Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET gestartet wurden und alle Aktivitäten, die über diesen Aktivitäten liegen). HINWEIS: Die Root-Aktivität wird in diesem Fall niemals gelöscht.

WICHTIGER HINWEIS: Wenn Sie testen, bitte beachten Sie, dass Android verhält sich ein Unterschied in der Art und Weise gibt es, wenn Apps aus dem HOME-Bildschirm (oder aus der Liste der verfügbaren Anwendungen) startet und bei der Auswahl Aufgaben aus der letzten Aufgabenliste.

Im ersten Fall (Starten einer App durch Auswahl aus der Liste der verfügbaren Anwendungen oder aus einer Verknüpfung auf dem HOME-Bildschirm) wird ein Starter Intent mit Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED erstellt. Dies wird unabhängig davon verwendet, ob die App bereits ausgeführt wird oder nicht.Die Intent wird gestartet und dann die ActivityManager herauszufinden, was zu tun ist.

Im zweiten Fall (Auswahl einer Aufgabe aus der Liste der letzten Aufgaben), wenn die Aufgabe noch existiert, wird es nur an die Front gebracht. Die Aufgabe "Zurücksetzen" wird NICHT ausgeführt, wenn die Aufgabe nur über die Liste der letzten Aufgaben in den Vordergrund gebracht wird. Es ist für mich nicht offensichtlich, wie dies gehandhabt wird und ich hatte keine Chance, den Quellcode durchzusehen, um herauszufinden, warum das so ist.


Ich hoffe, das beantwortet Ihre Fragen. Ich freue mich auf Ihre Rückmeldungen und Testergebnisse.

+1

Vielen Dank! Ich werde am Wochenende einige Tests durchführen. – CommonsWare

+0

Erste Runde der Tests mit [dieser Beispiel-App] (https://github.com/commonsguy/cw-omnibus/tree/master/Tasks/TaskCanary). Ich kann Ihre 'CLEAR_TOP | SINGLE_TOP'- und' NEW_TASK | CLEAR_TASK'-Ergebnisse mit zwei Noten reproduzieren. Erstens, 'startActivity()' mit 'CLEAR_TOP | SINGLE_TOP', um die aktuelle Top-Aktivität zu starten, hat keinen Effekt - es startet nicht einmal eine zweite Kopie, die zu den' CLEAR_TOP'-Dokumenten passt. – CommonsWare

+0

Zweitens, 'startActivity()' mit 'NEW_TASK | CLEAR_TASK' funktioniert wie erwartet, solange die Aktivitäten von Ihrer App stammen. Wenn die Aktivität, die Sie starten, von einer anderen App stammt, auch wenn diese keine Task-Affinität aufweist, scheint sie eine aufgabenlose Aktivität zu starten. Klicken Sie in meiner Beispielanwendung im Überlauf der Startaktivität auf "Andere Aktivität" und dann auf die Schaltfläche "Einstellungen - Aktivität, CLEAR_TASK | EINZEL_TASK". Der Bildschirm für die Datumseinstellungen wird angezeigt. Drücken Sie auf HOME. Gehen Sie dann in die Liste der letzten Aufgaben und kehren Sie zu TaskCanary zurück, und Sie werden mit den Schaltflächen zur Aktivität geführt. Es gibt keine Aufgabe für die App "Einstellungen". Seltsam. – CommonsWare

2

Ich könnte mich hier irren, aber in meinem Verständnis FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_RESET_TASK_IF_NEEDED analysiert alle Aufgaben und stellt sicher, dass nur eine Aufgabe mit Launcher-Aktivität ausgeführt wird.

FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP prüft nur die aktuelle Aufgabe, sodass Sie möglicherweise 2 Launcher-Instanzen gleichzeitig ausführen (wenn die erste als separate Aufgabe erstellt wurde).

+0

Das macht Sinn. Ich muss ein paar Experimente machen. Vielen Dank! – CommonsWare

+0

Ich bin nicht sicher, wie Sie mehr als 1 Aufgabe mit der Launcher-Aktivität ausführen können, es sei denn, Sie verwenden 'Intent.FLAG_ACTIVITY_MULTIPLE_TASK', die wirklich nur verwendet werden sollten, wenn Sie einen HOME-Bildschirm ersetzen und nur dann, wenn Sie einen Weg anbieten um zwischen mehreren Aufgaben zu unterscheiden, die dieselbe Stammaktivität ausführen. –

0

1) FLAG_ACTIVITY_RESET_TASK_IF_NEEDED

Wenn einige Aufgabe anhängig ist, als es diesen Prozess zerstören und die Aktivität starten, die von Ihnen angeforderte

2) FLAG_ACTIVITY_CLEAR_TOP

Wenn eine frühere Absicht dieser Aktivität ist ausgeführt, dann liefert diese Methode die laufende Instanz der Aktivität, schließt alle anderen Aktivitäten und startet die Aktivität mit der vorherigen Instanz.

3) FLAG_ACTIVITY_SINGLE_TOP

Wenn vor kurzem diese Aktivität ins Leben gerufen wurde, und die Instanz gespeichert ist, als es diese Aktivität nicht starten wird.

+0

Dies ist nur eine Nachahmung der Dokumentation, von denen viele bereits in der Frage zitiert werden. – CommonsWare

+0

Ich verändere (verbessere und erläutere), warte auf wenige bis ich die Erklärung beende –

+0

Prüfe die Antwort jetzt –

Verwandte Themen