2010-10-21 11 views
7

Wszystko,Android NDK: jak wyczyścić kod natywny po ponownym uruchomieniu działania?

Jestem świadomy, że domyślnie działanie zostanie zabite i uruchomione ponownie po zmianie orientacji ekranu lub wsunie lub zsunie się klawiatura. (Patrz Activity restart on rotation Android). Moje pytanie brzmi, jaki jest prawidłowy sposób obsługi tego z perspektywy kodu macierzystego? na przykład jeśli mam statyczny blok ładujący natywną bibliotekę i moja aplikacja jest ponownie uruchamiana, jak mogę zapewnić, że każda pamięć w rodzimej krainie jest odpowiednio traktowana? Problemem jest

Kiedy obrócić urządzenie, wygląda jak oddzielny basen Temat jest tworzony a stare nie są usuwane. To oznacza, że ​​za każdym razem ktoś włącza urządzenie, mamy mnóstwo więcej wątków siedzi bezczynnie i podejmowania pamięć

Jak mogę upewnić się, że tak się nie stanie? Widzę ze JNIExample page niektórych notatek na dole:

[*] Nierozwiązane problemy i błędy Nawet chociaż Przykładem jest całkowicie funkcjonalne, istnieje kilka nierozwiązane kwestie pozostałe, które nie był w stanie dowiedzieć się do tej pory. Problemy pojawiają się po rozpoczęciu działania , a następnie naciśnij przycisk Wstecz, aby ukryć, a następnie uruchomić go ponownie. Z mojego doświadczenia wynika, że ​​połączenia z rodzimymi funkcjami w takiej ponownie uruchomionej działalności zakończy się niepowodzeniem. callVoid() prostu wywala z segmentacja winy, natomiast wywołań getNewData() i getDataString() powodują JVM, aby przerwać z błędem, ponieważ nie jest już zadowolony z pamięci podręcznej globalnie obiekt odniesienia. Wydaje się, że aktywność restart jakoś unieważnia nasze buforowane odwołań do obiektów, choć są chronione NewGlobalRef() i aktywność pracuje w oryginalny JVM (aktywność restarcie nie nie znaczy, że sama JVM wznowiona) . Nie mam dobrego wyjaśnienia, dlaczego tak się dzieje, więc jeśli masz jakieś pomysły, proszę daj mi znać: .

Czy to rozwiązano?

Odpowiedz

6

Ponowne uruchamianie w systemie Android NDK jest denerwujące. Wszelkie statyczne dane, które przechowujesz, ponieważ ponownie wykorzystują proces, więc musisz ręcznie zresetować wszystko, co będzie nieprawidłowe w nowym przebiegu (jak każda tekstura OpenGL lub obiekty bufora wierzchołków).Daje nowy wątek Java i nową aplikację Java oraz inne obiekty, więc wszelkie buforowane globalne odwołania do obiektów, które będą nowe w nowej instancji aplikacji, również muszą zostać wyczyszczone.

Tak więc strategia, której używam, jest dwojaka: zminimalizuj ponowne uruchamianie i nukeuj wszystko po ponownym uruchomieniu.

Minimalizujesz ponowne uruchamianie, korzystając z opcji configChanges w aplikacji, zgodnie z odpowiedzią na pytanie, które łączysz. Wtedy otwarcie klawiatury lub obracanie nie spowoduje restartu aplikacji, tak jak powinno być w przypadku każdej aplikacji z nie trywialnym czasem uruchamiania.

Po wykryciu, że nowa instancja mojej aplikacji została uruchomiona, wydaję wszystko, co jest krytyczne ze starej instancji w tym momencie, włączając w to zwolnienie wszystkich obiektów Java, które posiadałem za pośrednictwem NewGlobalRef. Próbowałem zminimalizować dane statyczne, ale kilka nieuniknionych miejsc, w których zajmowałem się statycznymi obiektami, czyściłem je po wykryciu uruchomienia nowej instancji.

Stare wątki powinny zniknąć, gdy nie będzie już żadnych zaległych odniesień do nich (tj. Po zwolnieniu wszystkich obiektów NewGlobalRef).

2

Jeśli maszyna wirtualna zostanie ponownie uruchomiona, rozpoczniesz od zera. Jeśli nie, stan jest dokładnie tam, gdzie go zostawiłeś. Nie ma żadnego unieważnienia buforowanych odwołań do obiektów, które szarpią rzeczy poza NowąKlobalRef. Napisałem kilka innych uwag na temat artykułu wooydu on the NDK mailing list.

Jeśli masz dane, które muszą zostać zainicjalizowane po ponownym uruchomieniu działania, dodaj jednoznaczne wywołanie inicjujące do swojej aktywności (w trybie onCreate, myślę). Upewnij się, że właściwie wyrzuć wszystkie rzeczy, które zatrzymałeś z poprzedniej rundy - DeleteLocalRef następnie przechowuj NULL, nie tylko memset() do zera.