Активность просочилась в окно/диалог (это снова!)

Да, я прочитал бесчисленные вопросы относительно проблемы очень же.

Мой код прост: я просто использую showDialog(int id) в onCreate, а затем поворачиваю устройство. Код - это просто (тестовый пример), и этого достаточно, чтобы вызвать проблему. Я понял, что методы showDialog позаботятся об этом... диалог исчезнет, ​​а затем onCreate будет вызван позже после изменения и снова покажет диалог. Но нет. Что не так с этим рассуждением?

Я (думаю, я) понимаю причину, но я не знаю, как это решить. Даже приложение iosched имеет ту же проблему с их внедрением окна EULA (изменение ориентации в диалоге eula и вы получаете утечку). Я читал об отключении диалога onPause, но 1) я рискую уклоняться, когда он еще не показан, и 2) отслеживание диалога кажется слишком большим. Должен быть более надежный подход.

Итак... какой чистый код нужен для его обработки?

Спасибо.


Выход ошибки журнала:

01-30 00:27:18.615: E/WindowManager(20316): Activity com.test.PreSetupActivity has leaked window [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)

Ответы

Ответ 1

У вас есть внутренний класс, который действует как ваш государственный держатель и имеет там логическое поле, которое указывает, показывает ли ваш диалог. Отслеживайте это через изменения ориентации с помощью onRetainNonConfigurationInstance и просто повторно показывайте диалог на onResume

Вот код + псевдокод:

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() {}
  }

}