屏幕方向改变后关闭对话框

15

1)我通过AsyncTask启动了一个后台任务

new FindJourneyTask().execute(); // FindJourneyTask extends AsyncTask

2) 在主线程中 (在新线程启动之前),我使用showDialog(dialogId)创建一个对话框

// this method is in FindJourneyTask
protected void onPreExecute() {
    showDialog(DIALOG_FINDING_JOURNEY);
}

3) 屏幕方向改变时,Activity将重新创建

4) 我现在该如何关闭FindJourneyTask中的对话框?调用dismissDialog(dialogId)没有任何反应。

// this method is in FindJourneyTask
protected void onPostExecute(FindJourneyResult result) {
    dismissDialog(DIALOG_FINDING_JOURNEY); // does nothing
}

发布你的代码,这样我们就可以看到你做错了什么。 - Michael Pardo
6个回答

22

这是一个常见的问题,目前没有真正好的解决方案。问题在于屏幕方向改变时,整个Activity都被销毁并重新创建。同时,之前的对话框在新Activity中重新创建,但旧的后台任务仍然引用旧Activity,当它试图关闭对话框时,结果是关闭了一个早就被销毁的对话框,而不是关闭新方向创建的对话框。

有三种基本解决方案:

  1. 覆盖默认的方向处理代码,使您的Activity在旋转时不被销毁。这可能是最不令人满意的答案,因为它会阻止自动运行的许多代码。

  2. 创建一个静态成员变量,引用Activity本身,这样你可以调用STATIC_ACTIVITY_VARIABLE.dismissDialog()来关闭对话框。

  3. 编写一个解决方案,在其中后台任务跟踪当前Activity,并根据需要更新自己。

这三种解决方案在此处详细讨论:http://groups.google.com/group/android-developers/browse_thread/thread/bf046b95cf38832d/


我将我的对话框设置为活动中的静态变量,现在它完美地工作了。例如:static AlertDialog dlg_error = null; - Kevin

11
现在有一种更好的解决方案,涉及使用片段。
如果使用DialogFragment创建对话框,则该片段将负责维护对话框的生命周期。当您显示对话框时,提供DialogFragment.show()的标记(tag)来创建您的片段。当您需要访问对话框时,只需使用FragmentManager.findFragmentByTag查找所需的DialogFragment,而不是引用对话框本身。
这样,如果设备改变方向,您将获得一个新的片段,而不是旧的片段,并且一切都将正常工作。
以下是基于@peresisUser答案的一些代码:
public void onSaveInstanceState(Bundle outState) {
   AppCompatActivity activity = (AppCompatActivity) context;
   FragmentManager fragmentManager = activity.getSupportFragmentManager();
   DialogFragment dialogFragment = (DialogFragment) fragmentManager.findFragmentByTag("your_dialog_tag");
   if(dialogFragment!=null) {
      Dialog dialog = dialogFragment.getDialog();
      if(dialog!=null && dialog.isShowing()) {
         dialogFragment.dismiss();
      }
   }
}

1
即使使用片段,我仍然遇到了相同的问题。当活动被重新创建并尝试通过标签查找片段时,我总是在新活动中显示对话框时得到空引用。O_o - fr4gus
@fr4gus 这可能是一个bug,你需要尝试一些方法来找到解决办法。 - Malcolm

4

这个问题早已被问答过,但我也遇到了这个问题并想分享我的解决方案...

在onSavedInstance()方法中,我检查对话框是否正在显示,使用dialog.isShowing()方法,并将其传递给outState变量。然后在您的onCreate()方法中,如果这个变量为true,您只需使用dialog.dismiss()方法关闭对话框即可。

希望这能帮助其他人 :()


为什么你不在onSavedInstance中dismiss对话框呢? - Stoycho Andreev

2
我尝试在 DialogFragmentOnCreate 函数中添加 setRetainInstance(true);。这将导致对话框在旋转时关闭。

0
只需在您的清单文件中特定活动处添加以下行以解决此问题:android:configChanges="orientation|screenSize|smallestScreenSize" 就像这样,
        <activity
            android:name=".PDFTools"
            android:exported="false"
            android:configChanges="orientation|screenSize|smallestScreenSize"
            android:theme="@style/Theme.DocScanner.NoActionBar" />

0
一个非常简化的解决方法:
public class RenameDeckDialog extends DialogFragment{
      
  private final boolean isRotated;
  
  // This constructor is used to recreation after screen rotation
  public RenameDeckDialog() {
    // Dimiss on screen rotation
    isRotated = true;
  }
  
  // This constructor is used for initialization for the first time
  public RenameDeckDialog(your params) {
    this.deckDbPath = deckDbPath;
    isRotated = false;
  }

  @Override
  public void onResume() {
    super.onResume();
    if (isRotated) dismiss();
  }
}

根据目前的写法,你的回答不够清晰。请编辑以添加更多细节,帮助其他人理解这如何回答所提出的问题。你可以在帮助中心找到关于如何撰写好回答的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接