2012-01-30 10 views
14

Tak, przeczytałem niezliczone pytania dotyczące bardzo podobny problem.Aktywność wyciekła okno/dialog (to znowu!)

Mój kod jest prosty: po prostu używam showDialog(int id) na onCreate, a następnie obracam urządzenie. Kod jest właśnie taki (przypadek testowy) i to wystarczy, aby spowodować problem. Rozumiem, że za pomocą metod, które ... showDialog zajmie się tym ... dialog zniknie, a następnie onCreate zostanie wywołany później po zmianie i ponownie wyświetli okno dialogowe. Ale nie. Co jest nie tak z tym rozumowaniem?

Ja (myślę) rozumiem the cause, ale nie wiem, jak to rozwiązać. Nawet aplikacja iosched ma ten sam problem z implementacją okna EULA (zmiana orientacji w oknie dialogowym eula i dostaniesz wyciek). Czytałem o odrzuceniu okna dialogowego onPause, ale 1) ryzykuję odrzucenie, gdy nie jest ono już pokazywane, a 2) śledzenie dialogu wydaje się zbyt dużym wysiłkiem. Musi istnieć bardziej zdecydowane podejście.

Więc ... jaki jest dokładniejszy kod, który jest potrzebny do obsługi tego?

Dziękuję.


Log Wyjście błędu:

01-30 00:27:18.615: E/WindowManager(20316): Activity com.test.PreSetupActivity has leaked window com.android.internal.policy.impl.PhoneWindow$D[email protected] that was originally added here 
01-30 00:27:18.615: E/WindowManager(20316): android.view.WindowLeaked: Activity com.test.PreSetupActivity has leaked window [email protected] that was originally added here 
01-30 00:27:18.615: E/WindowManager(20316):  at android.view.ViewRootImpl.<init>(ViewRootImpl.java:343) 
01-30 00:27:18.615: E/WindowManager(20316):  at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:245) 
01-30 00:27:18.615: E/WindowManager(20316):  at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:193) 
01-30 00:27:18.615: E/WindowManager(20316):  at android.view.WindowManagerImpl$CompatModeWrapper.addView(WindowManagerImpl.java:118) 
01-30 00:27:18.615: E/WindowManager(20316):  at android.view.Window$LocalWindowManager.addView(Window.java:537) 
01-30 00:27:18.615: E/WindowManager(20316):  at android.app.Dialog.show(Dialog.java:274) 
01-30 00:27:18.615: E/WindowManager(20316):  at com.test.PreSetupActivity.onCreate(PreSetupActivity.java:88) 
01-30 00:27:18.615: E/WindowManager(20316):  at android.app.Activity.performCreate(Activity.java:4465) 
01-30 00:27:18.615: E/WindowManager(20316):  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1049) 
01-30 00:27:18.615: E/WindowManager(20316):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1919) 
01-30 00:27:18.615: E/WindowManager(20316):  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1980) 
01-30 00:27:18.615: E/WindowManager(20316):  at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3347) 
01-30 00:27:18.615: E/WindowManager(20316):  at android.app.ActivityThread.access$700(ActivityThread.java:122) 
01-30 00:27:18.615: E/WindowManager(20316):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1150) 
01-30 00:27:18.615: E/WindowManager(20316):  at android.os.Handler.dispatchMessage(Handler.java:99) 
01-30 00:27:18.615: E/WindowManager(20316):  at android.os.Looper.loop(Looper.java:137) 
01-30 00:27:18.615: E/WindowManager(20316):  at android.app.ActivityThread.main(ActivityThread.java:4340) 
01-30 00:27:18.615: E/WindowManager(20316):  at java.lang.reflect.Method.invokeNative(Native Method) 
01-30 00:27:18.615: E/WindowManager(20316):  at java.lang.reflect.Method.invoke(Method.java:511) 
01-30 00:27:18.615: E/WindowManager(20316):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784) 
01-30 00:27:18.615: E/WindowManager(20316):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551) 
01-30 00:27:18.615: E/WindowManager(20316):  at dalvik.system.NativeStart.main(Native Method) 
+0

widzę niektórzy ludzie są śledzenie okien, w zasadzie ich tworzenie bez metody 'showDialog' i sprawdzania, czy są wyświetlane (' isShowing() '), a następnie odpowiednio (w onStop/onPause). Uważam jednak, że można bezpiecznie powiedzieć, że automatyczny sposób (showDialog) powinien być bardziej przejrzysty i łatwiejszy, prawda? – davidcesarino

+0

możesz zamknąć okno dialogowe w onPostexecute(), np. Dialog.dismiss(); – user3114805

+0

Zamiast tego użyłbym DialogFragment. Automatycznie zarządza obrotem, dzięki czemu jest bardziej elegancki. – WindRider

Odpowiedz

13

mieć wewnętrzną klasę, która działa jako stateholder i mieć pole logiczną tam która wskazuje, czy Twój dialogowe jest wyświetlane. Śledzić to całej orientacji zmienia się za pomocą onRetainNonConfigurationInstance i po prostu ponownie wyświetlić okno na onResume

Oto kod + pseudo-kod:

public class ProfileActivity extends Activity { 
    private StateHolder mStateHolder; 
    private Dialog dialog; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    Object retained = getLastNonConfigurationInstance(); 
    if (retained != null && retained instanceof StateHolder) { 
     mStateHolder = (StateHolder) retained; 
    } else { 
     mStateHolder = new StateHolder(); 
    } 
    } 

    @Override 
    public Object onRetainNonConfigurationInstance() { 
    return mStateHolder; 
    } 

    @Override 
    public void onPause() { 
    super.onPause(); 
    if(dialog != null && dialog.isShowing()) { 
     dialog.dismiss(); 
    } 
    } 

    @Override 
    public void onResume() { 
    if(mStateHolder.mIsShowingDialog) { 
     dialog.show(); 
    } 
    } 

    private void showDialog() { 
    mStateHolder.mIsShowingDialog = true; 
    dialog.show(); 
    } 

    private static class StateHolder { 
    boolean mIsShowingDialog; 
    public StateHolder() {} 
    } 

} 
+0

Hmmm, niestety, przekonuję się, że 'showDialog' to po prostu PITA (przepraszam). Wypróbuję to rozwiązanie w odniesieniu do ręcznych okien dialogowych i złoŜę raport. Dziękuję Ci! – davidcesarino

+1

Jeszcze raz dziękuję. Używam powyższej koncepcji i działa idealnie! Nawet bardzo często naciskałem Ctrl + F11 w emulatorze, zmieniając orientację około dwa razy na sekundę, wiele razy ... coś, czego użytkownik w normalnym telefonie nigdy by nie zrobił. A moje linie logu były tak czyste, jak to tylko możliwe. Dziękuję bardzo, ponieważ wczoraj straciłem trochę czasu. – davidcesarino

+0

Świetna odpowiedź, użyłem 'onPause()' – rahstame

Powiązane problemy