1

我有一堆获取数据的异步任务。它们在执行时通过显示对话框来更新进度。有时这会导致应用在后台(不可见)时崩溃。我的代码在下面调用。在不完全重构对话框的情况下,我可以做哪些检查来防止应用程序崩溃?

这些在 DownloadAsyncTask 中声明并在构造函数中传递

protected ProgressDialog mDialog;
protected String mDialogMessage = "Loading Data";
protected ProgressBar progBar;

doInBackground() {
    if ( mProgressBar != null && mProgressBar.getVisibility() == View.INVISIBLE) {
        mUIThreadHandler.post(new Runnable() {
            @Override
            public void run() {
                mProgressBar.setVisibility(View.VISIBLE);
            }
        });
    } else if ( mDialog != null && !mDialog.isShowing() ) {
        mUIThreadHandler.post(new Runnable() {
            @Override
            public void run() {
                mDialog.setMessage(mDialogMessage);
                mDialog.show();
            }
        });
    }
}

然后onPostExecute()

@Override
protected void onPostExecute(DefaultHandler handler) {
    super.onPostExecute(handler);
    if ( progBar != null && progBar.getVisibility() == View.VISIBLE ) {
        progBar.setVisibility(View.INVISIBLE);
    } else if ( mDialog != null && mDialog.isShowing() ) {
        try {
            mDialog.dismiss();
        } catch (Exception e) {
        }   
    }   
}

更新的崩溃日志:

12-20 15:19:15.802: E/AndroidRuntime(9529):
android.view.WindowManager$BadTokenException: 无法添加窗口——令牌android.os.BinderProxy@41a37908 无效;您的活动正在运行吗?12-20 15:19:15.802: E/AndroidRuntime(9529): 在 android.view.ViewRootImpl.setView(ViewRootImpl.java:567) 12-20 15:19:15.802: E/AndroidRuntime(9529): 在 android. view.WindowManagerGlobal.addView(WindowManagerGlobal.java:246) 12-20 15:19:15.802: E/AndroidRuntime(9529): 在 android.view.WindowManagerImpl.addView(WindowManagerImpl.java:69) 12-20 15:19: 15.802: E/AndroidRuntime(9529): 在 android.app.Dialog.show(Dialog.java:281) 12-20 15:19:15.802: E/AndroidRuntime(9529): 在 com.*.DownloadAsyncTask$2.run(下载AsyncTask.java:119) 12-20 15:19:15.802: E/AndroidRuntime(9529): at android.os.Handler.handleCallback(Handler.java:725) 12-20 15:19:15.802:

4

3 回答 3

1

您正在从后台线程触摸 UI。Android 技术上说“不要更新”,但最好将其理解为“不要在后台线程上与 UI 交互”。您的if声明本质上是说“如果(...)关于 UI 是正确的,则发布此任务以在未来某个时间在 UI 线程上执行”。当您Runnable在 UI 线程上执行时,UI 的状态可能已经改变。封装整个逻辑并将其发送到要执行的 UI 线程可能会更好。您可以通过组合Runnable您拥有的两个 s 并在一个 s 中发送来做到这一点post,但AsyncTask设计为您不需要直接与处理程序打交道。如果您调用publishProgress()doInBackGround ,它将在 UI 线程上向onProgressUpdate()成员。因此,更容易做的事情是结合你Runnable的 s 中的代码并移动到onProgressUpdate()方法。

就像是 -

   void onProgressUpdate() {
            if (mProgressBar != null && mProgressBar.getVisibility() == View.INVISIBLE) {
                mProgressBar.setVisibility(View.VISIBLE);
            } else if (mDialog != null && !mDialog.isShowing()) {
                mDialog.setMessage(mDialogMessage);
                mDialog.show();
            }
        }
于 2012-12-22T02:47:24.027 回答
1

您应该检查活动是否尚未完成。

用这个:

if (!isFinishing()) {
    mDialog.show();
    }

查看此页面以获取更多描述:

http://dimitar.me/android-displaying-dialogs-from-background-threads/

于 2019-04-06T07:30:33.223 回答
0

使用 runOnUiThread(runnable) 避免崩溃:这实质上是在 UI 线程上运行 run 方法中的代码段。将您想要在 run 方法中执行的所有 UI 操作包装起来,如下所示。

所以代码会是这样的:

yourActivity.runOnUiThread(new Runnable() {

            @Override
            public void run() {
                // whatever UI operations..
                ..
                mDialog.setMessage(mDialogMessage);
                mDialog.show();
            }

});

于 2012-12-22T05:29:51.967 回答