2012-06-19 6 views
11

Ich habe eine Android-Aktivität, die finish() innerhalb es onStop() aufruft, also wenn ich zu anderen Aktivitäten (einschließlich des Hauptmenüs) wechseln, wird die Aktivität heruntergefahren. Bis zu diesem Punkt funktioniert alles wie erwartet.onCreate() nach Ende() in onStop()

Allerdings, wenn ich die Anwendung erneut ausführen (manchmal nicht immer), merke ich, dass die Anwendung mit der gleichen PID wie die vorherige ausgeführt wird und es ruft wieder onCreate(). Ich habe keinen Anruf an onRestart() gesehen, also nehme ich an, dass onCreate() Aufruf direkt nach onStop() ausgeführt wird, was etwas gegen die activity lifecyce ist. Wenn die App eine neue PID verwendet, kann ich verstehen, warum onCreate() aufgerufen wird, da dies der Beginn der Aktivität ist.

Wer weiß, warum das passiert?

Ein bisschen über die App, die ich entwickle: Dies ist eine Unity + Vuforia + Android-Anwendung. Ich erstelle eine benutzerdefinierte Aktivität, weil ich eine native Benutzeroberfläche für Android erstellen muss (anstelle von Unity).

Ich fand ein ähnliches Problem in das Android-Projekt gemeldet: http://code.google.com/p/android/issues/detail?id=15331, aber ich bin mir nicht sicher, ob die Ursache die gleiche ist oder nicht.

Update: Von dem, was ich aus dem Protokoll zu sehen, die nach dem finish() Anruf, dort onDestroy() kein Anruf. Wenn das von mir erwähnte Problem jedoch auftritt (die Aktivität wird mit demselben Prozess gestartet), wird zu Beginn der Aktivität ein Aufruf an onDestroy() gesendet.

Update: Entschuldigung für das späte Update. Hier zeige ich einen Ausschnitt des Logcat.

## First run 

I/ActivityManager( 265): Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=the.app/the.app.UnityAriusActivity bnds=[238,115][351,273] } from pid 423 
I/ActivityManager( 265): Start proc the.app for activity the.app/the.app.UnityAriusActivity: pid=1686 uid=10013 gids={3003, 1006, 1015} 
D/arius (1686): UnityAriusActivity: onStart 
D/arius (1686): UnityAriusActivity: onResume 

## Home button is pressed 

I/ActivityManager( 265): Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10200000 cmp=com.sonyericsson.home/.HomeActivity } from pid 265 
D/arius (1686): UnityAriusActivity: onPause 
D/arius (1686): UnityAriusActivity: onStop 

## Second run 

I/ActivityManager( 265): Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=the.app/the.app.UnityAriusActivity bnds=[238,115][351,273] } from pid 423 

## Same process, onStart is called again 

D/arius (1686): UnityAriusActivity: onStart 
D/arius (1686): UnityAriusActivity: onResume 
I/ActivityManager( 265): Displayed the.app/the.app.UnityAriusActivity: +500ms 
D/Unity (1686): Creating OpenGL ES 2.0 context (RGB16 565 16/0) 
W/IInputConnectionWrapper( 423): showStatusIcon on inactive InputConnection 
I/QCAR (1686): onSurfaceCreated 

## Strangely, there's an onDestroy here 

D/arius (1686): UnityAriusActivity: onDestroy 

## Unity apparently kills the process from its onDestroy 

I/Process (1686): Sending signal. PID: 1686 SIG: 9 
I/ActivityManager( 265): Process the.app (pid 1686) has died. 

Das Problem ist, dass es eine onDestroy() nach onStart() auf dem zweiten Lauf ist. Meine Aktivität ist im Grunde eine Unterklasse der Vuforia/QCAR-Aktivität, die auch eine Unterklasse der Aktivität von Unity ist. Also, in meinem onDestroy(), mache ich einen Aufruf an die Oberklasse '(super.onDestroy()) und auch das gleiche für die anderen Methoden, die ich überschreibe.

Wenn ich die Unity und Vuforia/QCAR Android Bibliothek angeschaut habe (ich war neugierig, also habe ich sie dekompiliert - ja, das könnte nicht stimmen), in Unity onDestroy() versucht Unity seinen eigenen Prozess zu töten (was die Anwendung ist verarbeiten).

Process.killProcess(Process.myPid()); 

Also, wenn das passiert, meine App gerade wieder heruntergefahren. Wenn der zweite Lauf einen anderen Prozess verwendet, passiert dieser seltsame onDestroy() nicht.

Ich habe auch den noHistory Ansatz versucht. . Aber das Gleiche noch passiert :(Wenn der zweite Lauf das gleiche Verfahren verwendet, ein spätes onDestroy() erscheinen und dann wird der Prozess durch Unity töten

+0

Ich muss auch 'finish()' aufrufen, wenn der Benutzer die Home-Taste drückt. Deshalb rufe ich es von 'onStop()'. – fajran

+0

Jeder Aufruf von finish() erzwingt onCreate erneut auszuführen, da dies die Aktivität –

+1

zerstört. Was genau ist das Problem hier? Das onDestroy() wird nicht aufgerufen? Oder dass es aufgerufen wird?Der Aktivitätslebenszyklus scheint es erforderlich zu machen, dass Sie mit beiden Möglichkeiten umgehen. –

Antwort

3

In der Dokumentation, die in Verbindung, die Beschreibung der onDestroy ist:

der letzte Anruf erhalten Sie vor Ihrer Aktivität zerstört wird. dieses entweder geschehen, weil die Aktivität zu beenden ist (jemand genannt finish() darauf oder weil das System vorübergehend diese Instanz der Aktivität zerstört wird um Platz zu sparen.Sie können diese beiden Szenarien mit der isFinishing() -Methode zwischen unterscheiden.

Während für onStop ist:

aufgerufen, wenn die Aktivität nicht länger für den Benutzer sichtbar ist, weil weitere Aktivität wieder aufgenommen wurde und dieses abdeckt. Dies kann passieren, entweder weil eine neue Aktivität gestartet wird, eine bestehende wird vor diese gebracht, oder diese wird zerstört. Gefolgt von entweder onRestart(), wenn diese Aktivität auf zurückkommt Interaktion mit dem Benutzer, oder onDestroy(), wenn diese Aktivität weggeht.

Das bedeutet, dass finish() Anrufe onDestroy nicht OnStop, so dass, wenn die Aktivität neu gestartet wird, onCreate genannt werden müssen, da auf Ihren Anruf finish() innerhalb onStop wird onDestroy zwingen zu laufen.

+0

Ja, ich verstehe diesen Teil. Ich möchte die Aktivität beenden, wenn sie inaktiv ist (d. H. 'OnStop()'). Deshalb rufe ich 'finish()' in 'onStop()' auf. – fajran

12

Sie machen einen verständlichen, aber kritischen Fehler in der Annahme, dass eine neue Aktivität in einem neuen Prozess ausgeführt werden muss. Bei Android ist dies nicht der Fall - Sie können die onCreate() einer neuen Aktivitätsinstanz in einem Prozess ausführen lassen, der nach dem Hosten einer früheren Aktivitätsinstanz beibehalten wurde.

Dies kann alles, was in Bezug auf einen Prozess statisch (vor allem, wenn auch nicht ausschließlich im nativen Code) ist, rätselhaft unzuverlässig machen.

Da die Aktivität, die gestartet wird, eine neue ist, erhält sie keine onRestart() - das würde nur passieren, wenn Sie eine vorhandene Aktivität neu starten würden.

+0

Sie sagen also, dass es für eine völlig neue Aktivität (in Bezug auf seinen Lebenszyklus) möglich ist, den vorherigen Prozess wiederzuverwenden? – fajran

+0

Ich habe gerade meine Frage aktualisiert. Wenn die Aktivität erneut mit demselben Prozess gestartet wird, sehe ich einen Aufruf von 'onDestroy()', der angeblich nach dem 'finish()' Aufruf erfolgt. Das ist eigentlich, was ich nicht will. – fajran

+2

Es gibt keine Garantie dafür, dass onDestroy() ausgeführt wird, insbesondere wenn der Prozess entsorgt wird. Sehen Sie sich dazu die Spalte "Killable" im Activity Lifecycle-Diagramm an. –

5

Warum setzen Sie nicht einfach noHistory="true" auf den Manifesteintrag der Aktivität? Dann müssen Sie sich nicht darum sorgen, die Aktivität in onStop() manuell zu beenden.

Suche nach Nohistory in http://developer.android.com/guide/topics/manifest/activity-element.html

Oder setzen Sie alternativ die FLAG_ACTIVITY_NO_HISTORY in Ihrer startActivity() Absicht. http://developer.android.com/reference/android/content/Intent.html#FLAG%5FACTIVITY%5FNO%5FHISTORY

+0

@fajran - Ich hätte oben erwähnt, dass die Art, wie Sie 'finish()' in 'onStop()' nennen, wie ein Hack aussieht. Gibt es einen guten Grund dafür, dass Sie keine plattformfreundlichere Methode verwenden, um zu verhindern, dass Ihre Aktivität in den Verlaufsstapel aufgenommen wird? – Josh

+0

Ich denke, dass ich das tun, weil ich nicht über die NoHistory-Option wusste, ich bin relativ neu in Android-Entwicklung :) Wie auch immer .. Ich versuchte dies und leider sehe ich immer noch das Problem :( – fajran

+0

OK, sichern Sie ein wenig Ich habe gesagt, dass Sie das versucht haben. Welche Methode haben Sie versucht? Ich hoffe, dass Sie den 'finish()' Aufruf von 'onStop()' entfernt haben, als Sie diesen Test gemacht haben, oder? Was sind die genauen Dinge, die passieren wenn Sie noHistory haben 'set to' true'? Könnten Sie es so beschreiben wie "Öffnen Sie Aktivität A. Öffnen Sie Aktivität B von A. Drücken Sie auf Home. Öffnen Sie die App vom Startbildschirm. Immer noch Aktivität B!" – Josh

0

Ich laufe in ein ähnliches Verhalten: OnDestroy seltsamerweise nach onCreate/onStart/onResume aufgerufen, wenn die Aktivität gestartet wird. Ich habe keine definitive Bestätigung, aber mein Gefühl ist, dass der Aufruf onDestroy der vorherigen Aktivität entspricht, nicht der neuen. Aber aus irgendeinem Grund wird die Ausführung verzögert, bis der Prozess erneut aktiviert wird (wenn eine neue Aktivität gestartet wird).

Ich glaube, das ist wegen Aufruf "Finish()" von onStop. Ich habe in meinen Protokollen festgestellt, dass der Aktivitätsmanager sich darüber beschwert, dass die Aktivität gestoppt wurde, aber nicht mehr gestoppt wird (sie wird gerade beendet). Also frage ich mich, ob dies mit dem Zustand des Aktivitätsmanagers Dinge meiner Tätigkeit in Schwierigkeiten ist.

In Ihrem Fall ist das Endergebnis, dass der gesamte Prozess getötet wird, aufgrund der onDestroy Anruf. Wenn Ihre neue Aktivität im selben Prozess wie die vorherige gestartet wird, wird Ihre App sofort beendet.