2012-06-19 16 views
11

Mam aktywność Androida, która wywołuje finish() wewnątrz jej numeru onStop(), więc po przełączeniu się na inne czynności (w tym menu główne) działanie zostanie zamknięte. W tym momencie wszystko działa zgodnie z oczekiwaniami.onCreate() po zakończeniu() w onStop()

Jednak po ponownym uruchomieniu aplikacji (czasami nie zawsze) zauważam, że aplikacja działa z tym samym identyfikatorem PID co poprzedni i ponownie wywołuje onCreate(). Nie widzę żadnego połączenia z numerem onRestart(), więc zakładam, że wywołanie onCreate() jest wykonywane bezpośrednio po onStop(), co jest niezgodne z activity lifecyce. Gdy aplikacja używa nowego PID, mogę zrozumieć, dlaczego jest wywoływana onCreate(), ponieważ jest to początek działania.

Ktoś wie, dlaczego tak się stało?

Trochę o aplikacji, którą tworzę: Jest to aplikacja Unity + Vuforia + Android. Tworzę niestandardową aktywność, ponieważ muszę utworzyć macierzysty interfejs na Androida (zamiast z Unity).

Znalazłem podobny problem zgłoszony do projektu Android: http://code.google.com/p/android/issues/detail?id=15331, ale nie jestem pewien, czy przyczyna jest taka sama, czy nie.

aktualizacja: Z tego, co widzę z dziennika, po wywołaniu finish(), nie ma wezwanie do onDestroy(). Jeśli jednak pojawi się problem, o którym wspomniałem (aktywność jest uruchamiana przy użyciu tego samego procesu), na początku działania jest wywołanie onDestroy().

aktualizacja: Przepraszamy za późną aktualizację. Tutaj pokazuję fragment 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. 

Problemem jest to, że nie jest onDestroy() po onStart() na drugim biegu. Moja aktywność jest w zasadzie podklasą aktywności Vuforia/QCAR, która jest również podklasą działalności z Unity. Tak więc, w moim onDestroy(), nawiązuję połączenie z nadklasą "(super.onDestroy()) i tym samym dla innych metod, które nadpisuję.

Gdybym spojrzał na bibliotekę Unity i Vuforia/QCAR Android (byłem ciekawy, więc je zdekompilowałem - tak, to może nie być w porządku), wewnątrz Unity onDestroy(), Unity próbuje zabić swój własny proces (który jest aplikacją proces).

Process.killProcess(Process.myPid()); 

Kiedy to nastąpi, moja aplikacja ponownie się wyłączy. Jeśli drugi proces używa innego procesu, to nie dzieje się tak dziwnie.

Próbowałem również podejście nieHistory. . Ale wciąż to samo dzieje :(Kiedy drugi bieg wykorzystuje ten sam proces, późne onDestroy() pojawi, a następnie proces jest zabić przez Unity

+0

Muszę również wywołać 'finish()', gdy użytkownik naciśnie przycisk home. Właśnie dlatego wywołuję go z 'onStop()'. – fajran

+0

Każde wywołanie metody finish() wymusi na Utwórz ponownie, ponieważ spowoduje to zniszczenie działania –

+1

. Na czym dokładnie polega problem? Że onDestroy() nie jest wywoływany? Lub, że to się nazywa?Wydaje się, że cykl życia aktywności wymaga obsługi obu możliwości. –

Odpowiedz

3

w dokumentacji w link, opis onDestroy jest:

Ostateczne wezwanie pojawić przed swoją aktywność jest zniszczona. To może zdarzyć, albo dlatego, że aktywność kończy (ktoś nazywa wykończenie() na nim, albo dlatego, że system jest tymczasowo niszcząc tę ​​ wystąpienie aktywności aby zaoszczędzić miejsce.Można rozróżnić te dwa scenariusze za pomocą metody isFinishing().

Choć dla onStop jest:

Wywoływana, gdy działalność nie jest widoczna dla użytkownika, ponieważ inna działalność została wznowiona i zakrywa ten jeden. Może to być zdarzać się albo dlatego, że rozpoczyna się nowa aktywność, przed nią jest już istniejąca , albo ta jest niszczona. Następnie następuje onRestart(), jeśli ta aktywność powraca do interakcji z użytkownikiem lub onDestroy(), jeśli ta czynność zostanie przerwana.

Oznacza to, że finish() rozmowy onDestroy nie OnStop, więc gdy aktywność zostaje wznowiona, onCreate musi być wywołana, ponieważ wezwanie do finish() wewnątrz onStop zmusi onDestroy uruchomić.

+0

Tak, rozumiem tę część. Chcę zakończyć działanie, gdy jest nieaktywne (tj. 'OnStop()'). Dlatego nazywam 'finish()' wewnątrz 'onStop()'. – fajran

12

Dokonujesz zrozumiałego, ale krytycznego błędu, zakładając, że nowa aktywność musi działać w nowym procesie. Tak się nie dzieje na Androidzie - możesz mieć instancję onCreate() nowej instancji działania w procesie, który był utrzymywany po hostowaniu wcześniejszej instancji działania.

To może sprawić, że wszystko, co jest statyczne w odniesieniu do procesu (zwłaszcza, choć nie wyłącznie w natywnym kodzie), stanie się niewiarygodne.

Ponieważ uruchamiane działanie jest nowe, nie otrzyma onRestart() - może się zdarzyć tylko w przypadku ponownego uruchamiania istniejącej czynności.

+0

Mówisz, że możliwe jest całkowicie nowe działanie (w odniesieniu do jego cyklu życia), aby ponownie użyć poprzedniego procesu? – fajran

+0

Właśnie zaktualizowałem moje pytanie. Kiedy aktywność jest ponownie uruchamiana przy użyciu tego samego procesu, widzę wywołanie funkcji 'onDestroy()', która jest podobno wykonywana po wywołaniu 'finish()'. Tak naprawdę nie chcę się wydarzyć. – fajran

+2

Nie ma gwarancji, że zdarzenie onDestroy() będzie miało miejsce, szczególnie jeśli proces zostanie usunięty - spójrz na kolumnę, którą można usunąć na diagramie Activity Activity cycle. –

5

Dlaczego po prostu nie ustawisz noHistory="true" w manifeście działania? Wtedy nie musisz się martwić o ręczne zakończenie działania w onStop().

Szukaj Nohistory w http://developer.android.com/guide/topics/manifest/activity-element.html

lub, alternatywnie, ustawić FLAG_ACTIVITY_NO_HISTORY w startActivity() intencji. http://developer.android.com/reference/android/content/Intent.html#FLAG%5FACTIVITY%5FNO%5FHISTORY

+0

@fajran - Powinienem wspomnieć powyżej, że sposób, w jaki wywołujesz 'finish()' w 'onStop()', wydaje się być hackerem. Czy istnieje dobry powód, dla którego nie używasz bardziej przyjaznego dla platformy sposobu zapobiegania wchodzeniu aktywności w stos historii? – Josh

+0

Myślę, że to robię, ponieważ nie wiedziałem o opcji noHistory, jestem stosunkowo nowy w rozwoju Androida :) W każdym razie .. Próbowałem tego i niestety nadal widzę problem :( – fajran

+0

OK, zrób kopię zapasową. powiedziałeś, że próbujesz to, Którą metodę wypróbowałeś? Mam nadzieję, że usunąłeś wywołanie 'finish()' z 'onStop()' kiedy zrobiłeś ten test, prawda? Więc jakie są dokładne rzeczy, które się zdarzają kiedy masz 'noHistory "ustawić na" true "? Czy możesz opisać to jako" Otwórz działanie A. Otwórz działanie B z A. Naciśnij Strona główna Otwórz aplikację z ekranu głównego Nadal zobacz Aktywność B! " – Josh

0

Występuje podobne zachowanie: onDestroy dziwnie wywołuje funkcję onCreate/onStart/onResume, gdy aktywność jest uruchamiana. Nie mam jednoznacznego potwierdzenia, ale mam wrażenie, że połączenie onDestroy odpowiada poprzedniej aktywności, a nie nowej. Ale z jakiegoś powodu jego wykonanie jest opóźnione, dopóki proces nie zostanie ponownie aktywowany (przy rozpoczynaniu nowej aktywności).

Uważam, że jest to spowodowane wywołaniem "finish()" z onStop. Zauważyłem w moich dziennikach, że menedżer aktywności skarży się, że aktywność została zatrzymana, ale nie jest już zatrzymywana (w rzeczywistości kończy się). Zastanawiam się więc, czy nie ma to wpływu na stan menedżera aktywności, w którym znajduje się moja aktywność.

W twoim przypadku końcowy wynik jest taki, że cały proces zostanie zabity, z powodu połączenia onDestroy. Gdy twoja nowa aktywność rozpoczyna się w tym samym procesie co poprzednia, Twoja aplikacja natychmiast się kończy.

Powiązane problemy