Android AsyncTask中的AlertDialog

4
我有一个带复选框的列表视图。对于每个复选框(大约有3个),它都有一个特定的AsyncTask。
我不知道用户选择了哪些复选框,因此我不能在Async任务结束时放置AlertDialog,因为我不知道用户是否选择了一个、两个或三个复选框。
由于AsyncTask是分步执行的(只有第一个Async完成后才开始执行第二个),所以我考虑在所有操作结束后添加一个新的AsyncTask,并在其中包含一个AlertDialog。
private class showMessageAsync extends AsyncTask<Void, Integer, String> {
    @Override
    protected String doInBackground(Void... params){
        AlertDialog alertDialog;
        alertDialog = new AlertDialog.Builder(getApplicationContext).create();
        alertDialog.setTitle("The Process");  
        alertDialog.setIcon(R.drawable.success);
        alertDialog.setCanceledOnTouchOutside(false);
        alertDialog.setMessage("All done!");  
        alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK",
                              new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int which) {
                Intent A = new Intent(DownloadActivity.this, Menu_activity.class);
                startActivity(A);
                finish();
            }
        });
        alertDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {          
            @Override
            public void onDismiss(DialogInterface dialog) {
                Intent A = new Intent(DownloadActivity.this, Menu_activity.class);
                startActivity(A);
                finish();
            }
        });
        alertDialog.show();
        return "Executed";
    }
}

这是错误信息:

10-21 04:24:34.117: E/AndroidRuntime(1026): FATAL EXCEPTION: AsyncTask
#4 10-21 04:24:34.117: E/AndroidRuntime(1026): java.lang.RuntimeException: An error occured while executing
doInBackground() 10-21 04:24:34.117: E/AndroidRuntime(1026):    at
android.os.AsyncTask$3.done(AsyncTask.java:299) 10-21 04:24:34.117:
E/AndroidRuntime(1026):     at
java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:352)
10-21 04:24:34.117: E/AndroidRuntime(1026):     at
java.util.concurrent.FutureTask.setException(FutureTask.java:219)
10-21 04:24:34.117: E/AndroidRuntime(1026):     at
java.util.concurrent.FutureTask.run(FutureTask.java:239) 10-21
04:24:34.117: E/AndroidRuntime(1026):   at
android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230) 10-21
04:24:34.117: E/AndroidRuntime(1026):   at
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
10-21 04:24:34.117: E/AndroidRuntime(1026):     at
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
10-21 04:24:34.117: E/AndroidRuntime(1026):     at
java.lang.Thread.run(Thread.java:841) 10-21 04:24:34.117:
E/AndroidRuntime(1026): Caused by: java.lang.RuntimeException: Can't
create handler inside thread that has not called Looper.prepare()
10-21 04:24:34.117: E/AndroidRuntime(1026):     at
android.os.Handler.<init>(Handler.java:197) 10-21 04:24:34.117:
E/AndroidRuntime(1026):     at
android.os.Handler.<init>(Handler.java:111) 10-21 04:24:34.117:
E/AndroidRuntime(1026):     at android.app.Dialog.<init>(Dialog.java:107)
10-21 04:24:34.117: E/AndroidRuntime(1026):     at
android.app.AlertDialog.<init>(AlertDialog.java:114) 10-21
04:24:34.117: E/AndroidRuntime(1026):   at
android.app.AlertDialog$Builder.create(AlertDialog.java:931) 10-21
04:24:34.117: E/AndroidRuntime(1026):   at com.example.MyExample.DownloadActivity$showMessageAsync.doInBackground(DownloadActivity.java:487)
10-21 04:24:34.117: E/AndroidRuntime(1026): at com.example.MyExample.DownloadActivity$showMessageAsync.doInBackground(DownloadActivity.java:1)
10-21 04:24:34.117: E/AndroidRuntime(1026):     at android.os.AsyncTask$2.call(AsyncTask.java:287) 10-21 04:24:34.117:
E/AndroidRuntime(1026):     at java.util.concurrent.FutureTask.run(FutureTask.java:234) 10-21
04:24:34.117: E/AndroidRuntime(1026):   ... 4 more

I call my AsyncTask this way:

if(list.get(0).isSelected() == true){
    // list = class that contains checkboxs state
    String[] params = {order, String.valueOf(limit_customers) };
    customers.execute(params);
}
if(list.get(1).isSelected() == true){
    String[] params = {order, String.valueOf(limit_products) };
    products.execute(params);
}
// etc, and in the end of this:
showMessageAsync sM = new showMessageAsync();
sM.execute();

错误出现在这一行:
alertDialog = new AlertDialog.Builder(getApplicationContext()).create();
5个回答

24

警告对话框是前台事物,因此不能在异步任务的后台方法中完成。请按照以下方式执行:

private class showMessageAsync extends AsyncTask<String, Void, String> {
     AlertDialog alertDialog;
     protected void onPreExecute() {
    super.onPreExecute();
            alertDialog = new AlertDialog.Builder(YourClasss.this);  
     }
     @Override
     protected String doInBackground(Void... params){       
            return null;
     }
     @Override
     protected void onPostExecute(String result) {
            super.onPostExecute(result);

            alertDialog.setTitle("The Process");  
            alertDialog.setIcon(R.drawable.success);
            alertDialog.setCanceledOnTouchOutside(false);
            alertDialog.setMessage("All done!");  
            alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK",
                                  new DialogInterface.OnClickListener() {
                                        public void onClick(DialogInterface dialog, int which) {
                                                Intent A = new Intent(DownloadActivity.this, Menu_activity.class);
                                                startActivity(A);
                                                finish();
                                        }
                                    });
            alertDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {          
                                  @Override
                                  public void onDismiss(DialogInterface dialog) {
                                            Intent A = new Intent(DownloadActivity.this, Menu_activity.class);
                                            startActivity(A);
                                            finish();
                                  }
                    });
            alertDialog.show();
    }

}

我不确定这有什么收益?后台没有执行任何操作。帮助我理解。 - seekingStillness
@seekingStillness doInBackground,由你决定要做什么。这是在异步完成后打开对话框的代码。 - AnAndroid

4
由于:java.lang.RuntimeException:无法在未调用Looper.prepare()的线程中创建处理程序。
您正在尝试在doInbackground中显示a lertdialog。 doInbackground在后台线程上调用,ui应该在ui线程上更新。
您可以在doInbackground中返回后台计算结果,并在onPostExecute中更新ui。或使用activity类的runOnUiThread方法。或在onProgressUpdate(Progress ...)中显示对话框。

http://developer.android.com/reference/android/os/AsyncTask.html

同时在Threads下查看主题,链接为http://developer.android.com/guide/components/processes-and-threads.html

当应用程序启动时,系统会为应用程序创建一个执行线程,称为“main”。这个线程非常重要,因为它负责将事件分派给适当的用户界面小部件,包括绘制事件。它也是您的应用程序与 Android UI 工具包中的组件(来自 android.widget 和 android.view 包的组件)交互的线程。因此,主线程有时也被称为 UI 线程。

还需使用活动上下文

  alertDialog = new AlertDialog.Builder(ActivityContext).create();

我该怎么做呢?我需要在所有任务结束时显示一条消息,但我不知道用户选择了哪些任务。 - user2742861
我已经知道那些事件并且我确实使用它们。但请看我的回答 Dhara Shah 的第二个答案。 - user2742861
是的,我考虑过AsyncTask,因为它们一个接一个地执行。如果我在代码末尾放置一个简单的void方法“showMessage()”,它将立即执行,而不会等待AsyncTasks完成。 - user2742861
你可以使用handler来进行延迟操作,但我认为你不需要asynctask来完成你正在做的事情。请阅读我在帖子中发布的链接,然后决定是否使用asynctask。 - Raghunandan
1
@user2742861 欢迎您,一定要阅读文档,这将有助于您未来的发展。 - Raghunandan
显示剩余6条评论

3

你不能在doInBackground方法中调用警告框(alert box),同样,也不能使用toast。不允许在doInBackground方法中进行任何UI操作。应该使用postExecute方法或改变处理方式。


我应该怎么做呢?我需要在所有任务结束时显示一条消息,但我不知道用户选择了哪些任务。 - user2742861
让用户先选择项目,然后执行操作,这是唯一的方法 :) - Rat-a-tat-a-tat Ratatouille
啊?这已经完成了。用户选择项目后,任务就开始了。但是你怎么知道哪一个是最后一个,以便显示消息呢? - user2742861
很抱歉,但在执行方法时无法显示消息。您可以尝试搜索progressUpdate方法是否有帮助。但是这种方式不行。除非只是在所有操作结束时简单地显示一条消息 :).. - Rat-a-tat-a-tat Ratatouille
兄弟,这就是我想告诉你的。我无法在所有结束时显示“简单”的消息,因为第一,AsyncTask不能与alertDialog一起使用;第二,一个简单的调用'Message'的方法即使任务还没有完成也会运行。 - user2742861
所有任务都是在异步中执行的吗?跟踪所有已选择的项目,以及已执行的项目。检查已执行和剩余任务的计数器,并在onPostExecute方法中的if条件内向用户显示消息框。 - Rat-a-tat-a-tat Ratatouille

1
你可以在 doInBackground 函数内使用此方法访问用户界面:
getActivity().runOnUiThread(new Runnable() {
    @Override
    public void run() {
        if (!dialog.isShowing()) {
            dialog.show();
        }
        dialog.setMessage(getText(R.string.lbl_downloading) + " : " + String.valueOf(mCount) + " / " + String.valueOf(totalItems));
    }
});

这是从我的代码中提取的片段,用于显示已下载的项目。

0

通常在Java中,当您从另一个线程A调用线程B时,会发生3件事情

  1. onPreExecute:此方法属于线程A(调用者线程)
  2. doInBackground:此方法属于线程B(在此处执行一些工作)
  3. onPostExecute:此方法属于线程A(再次是调用者)

因此,如果您想显示一个警报,显示来自线程B的某些结果,则必须在onPostExecute方法中执行它,因为它属于线程A。

    @Override
    protected void onPostExecute(String result) {
        showDialogForResult(result);
    }

记住,showDialogForResult方法可以成为线程A中的类的一部分。


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