Android - dismissDialog无法关闭对话框

21

我使用showDialog()dismissDialog()在我的应用程序中显示进度对话框。从创建对话框并在其上调用show()转移到使用此方法以在更改方向时保存状态。

但是,当我从纵向模式->横向模式->纵向模式更改方向时,dismissDialog()不再关闭对话框。对话框一直停留在那里,我需要按返回按钮才能使其消失。

为什么会这样呢?

编辑

为了解决这个问题,我尝试在onDestroy()中添加removeDialog(),以便不会创建/显示两次对话框,并在更改方向之前删除对话框。尝试添加日志语句并查看发生了什么。

05-21 12:35:14.064: DEBUG/MyClass(193): *************callingShowDialog
05-21 12:35:14.064: DEBUG/MyClass(193): *************onCreareDialog

05-21 12:35:15.385: DEBUG/MyClass(193): *************onSaveInstanceState
05-21 12:35:15.415: DEBUG/MyClass(193): *************onDestroy

05-21 12:35:15.585: DEBUG/MyClass(193): *************callingShowDialog
05-21 12:35:15.585: DEBUG/MyClass(193): *************onCreareDialog
05-21 12:35:15.715: DEBUG/MyClass(193): *************onCreareDialog
05-21 12:35:17.214: DEBUG/MyClass(193): *************onSaveInstanceState
05-21 12:35:17.214: DEBUG/MyClass(193): *************onDestroy

05-21 12:35:17.275: ERROR/WindowManager(193): android.view.WindowLeaked: Activity com.android.MyClass has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@43362088 that was originally added here

05-21 12:35:17.395: DEBUG/MyClass(193): *************callingShowDialog
05-21 12:35:17.395: DEBUG/MyClass(193): *************onCreareDialog
05-21 12:35:17.475: DEBUG/MyClass(193): *************onCreareDialog
如果我们在这里看到,最初显示活动时,onCreateDialog将被调用一次,并且在更改方向时将调用onSaveInstanceState和onDestroy。

但之后,onCreateDialog会被调用两次(一次是由我调用showDialog引起的,但为什么还会有第二次?)并且每次我改变方向时都会发生这种情况。

有任何想法为什么会发生这种情况吗?

再次感谢


有人能帮我解决这个问题吗?我看过很多关于这个问题的帖子和博客,但似乎没有一个可行的解决方案。 - lostInTransit
8个回答

8

对我来说,最好的解决方案似乎是使用removeDialog(id)而不是dismissDialog();这种方式可以减少重复使用,更加安全(不会抛出异常),并且在更改方向时没有问题。


6

当我在Activity的onCreate重载中显示一个对话框时,我遇到了这个问题。尝试将引起对话框显示的代码移动到onPostCreate重载中。这对我来说似乎有用。


我在onCreate()中使用showDialog()时遇到了相同的问题-虽然这似乎只在通过调试器启动应用程序时发生。将showDialog()移动到onPostCreate()就解决了我的问题-谢谢! - sstn
很棒的解决方案,只需使用OnPostCreate来启动对话框... @Override public void onPostCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); launch_app(); }
- Michael Biermann
这是一个已记录的Android bug:http://code.google.com/p/android/issues/detail?id=24646 - Rémi

5
我浪费了一整天在这个问题上,当我调用dismissDialog时对话框没有被关闭。这发生在我第一次旋转屏幕之后,之后永远都没能正常工作。我一直在使用一个外部的AsyncTask,它被明确地传递了状态引用。
最后解决方案非常简单...使用removeDialog(int)而不是dismissDialog(int)。
我花了很长时间证明我在正确的活动中执行了dismiss,并检查了调用次数等,但它是由于幕后的某些混乱引起的。

4

我最近也遇到了这个问题。我的应用程序有许多活动,都需要访问全局对象(db连接、数据列表等),因此我重写了Application类。为此,我意识到,在我用于关闭对话框的可运行文件中,我只需要引用最新的进度对话框实例即可。以下是我想出来的解决方案,它可以优雅地处理手机重新定向:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    addPreferencesFromResource(R.xml.preferences);

    mHandler = new Handler();
    mApplication = (MyApplication)getApplication();

    mFileStorage = (CheckBoxPreference)getPreferenceScreen().findPreference("fileStorage");

    mProgressDialog = new ProgressDialog(this);

    mProgressDialog.setTitle("Location Update");
    mProgressDialog.setMessage("Moving databases to new storage location.");
    mProgressDialog.setIndeterminate(true);
    mProgressDialog.setCancelable(false);
    mProgressDialog.setCanceledOnTouchOutside(false);

    mApplication.setProgressDialog(mProgressDialog);
}

@Override
protected void onResume() {
    super.onResume();

    mPreferences = PreferenceManager.getDefaultSharedPreferences(this);
    mPreferences.registerOnSharedPreferenceChangeListener(this);

    if (sUpdateThread != null && sUpdateThread.isAlive()) {
        mProgressDialog.show();
    }
}

@Override
protected void onPause() {
    super.onPause();

    mPreferences.unregisterOnSharedPreferenceChangeListener(this);

    if (sUpdateThread != null && sUpdateThread.isAlive()) {
        mProgressDialog.hide();
        mApplication.setProgressDialog(null);
    }
}

抱歉,我没有看到需要翻译的内容。请提供具体的文本以便我进行翻译。
private Runnable showProgressRunnable = new Runnable() {
    public void run() {
        mProgressDialog.show();
    }
};

private Runnable hideProgressRunnable = new Runnable() {
    public void run() {
        if (mApplication.getProgressDialog() != null) {
            mApplication.getProgressDialog().dismiss();
        }
    }
};

当任务开始时,我的线程会执行mHandler.post(showProgressRunnable),然后在任务完成时执行mHandler.post(hideProgressRunnable)。由于最新ProgressDialog的引用现在存储在Application类中,因此我可以可靠地关闭它,因为我不再持有旧对象引用。

永久链接:http://developer.android.com/reference/android/app/Application.html


3

按下主页按钮并导航到更多本地应用(更改设备语言)后,当我回到我的应用程序时,无法通过dismissDialog关闭新的对话框(我从activity onCreate启动了对话框)。

解决方法是调用removeDialog而不是dissmissDialog()。这是Harri以上推荐的,非常感谢。

我已经创建了一个Android错误报告:

13858


解决方法是使用OnPostCreate而不是OnCreate创建您的对话框。我已将此信息添加到错误报告中,并建议改进对话框文档

0
请注意,每次更改方向时,都会创建您的Activity(因此也是通过onCreateDialog创建的Dialog)的新实例。您可以通过在任一构造函数中添加日志语句来验证这一点。
虽然没有查看您的代码很难说,但我猜测您正在调用旧版ActivitydismissDialog
考虑以下Activity,当单击按钮时显示一个空的Dialog并启动TimerTask以在10秒后关闭它:
public class Test extends Activity {

    private Dialog dialog;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);     
        setContentView(R.layout.test);
        Button btn = (Button) findViewById(R.id.testButton);
        btn.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                new Timer().schedule(new TimerTask() {
                    @Override public void run() { dialog.dismiss(); }
                }, 10000);
                Test.this.showDialog(1);
            }
        });
    }

    @Override
    protected Dialog onCreateDialog(int id) {
        if(id == 1) {
            if(dialog == null) { dialog = new Dialog(this); }
            return dialog;
        }
        return super.onCreateDialog(id);
    }
}

这段代码存在一个类似于您所描述的问题:如果在10秒内更改了方向,则Dialog永远不会被解除。 为什么?因为在TimerTask运行时,已经创建了一整套不同的TestDialog实例(在方向更改期间),而TimerTaskdialog实例变量引用的是与当前屏幕上活动的Test实例不同的Test实例。

显然,有几种方法可以处理此问题(主要取决于您的应用程序),修复上述代码的一种快速(肮脏?)的方法是将dialog字段简单地设置为static

private static Dialog dialog;

谢谢Josef。但正如你所说,那个修复方法实际上是一个hack!我正在考虑使用服务。在服务运行的同时,我会显示对话框。这样做是正确的方式吗? - lostInTransit
这真的取决于应用程序。但你是对的,(非常)长时间运行的任务一定要放到服务中。 - Josef Pfleger

0
在搜索了各种论坛之后,我终于找到了解决方法:
我从我的Handler的handleMessage(myMessage)方法中调用showDialog(MyDialogID)和dismissDialog(MyDialogId)。
在此之前,我在onCreate()方法中调用showDialog,并尝试在handleMessage()方法中dismiss对话框。为什么这样做可以解决问题,我也说不清楚。

0

我曾经遇到过同样的问题。我在onCreateDialog()回调函数中创建了一个AlertDialog和一个ProgressDialog,并在onCreate()中显示它们。直接在onCreate中创建这些对话框(而不使用onCreateDialog()),并在onPause()中关闭它们对我有用! 参考https://stackoverflow.com/a/5693467/955619


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