4

I have a listview which have checkboxes. For each checkbox (they are about 3), it has a specific AsyncTask for it.

I never know what checkboxes user chooses, so I cannot put in the end of the Async task the AlertDialog, because I never know if the user has chosen only one checkbox, or two or three.

Because the AsyncTask are executed in steps (only when the 1st Async is finished is when the second begins), I thought about put in the end of everything a new AsyncTask with an 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";
    }
}

And this is the error:

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();

The error is on this line:

alertDialog = new AlertDialog.Builder(getApplicationContext()).create();
rupesh
  • 2,865
  • 4
  • 24
  • 50
user2742861
  • 340
  • 1
  • 8
  • 17

5 Answers5

24

alert dialog is foreground thing so it can not be done in background method of async task. Do it by this way

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

}
AnAndroid
  • 567
  • 1
  • 5
  • 16
4

Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()

You are trying to display a lertdialog inside doInbackground. doInbackground is invoked on a backgroudn thread. and ui should be updated on the ui thread.

You can return result of background computation in doInbackground and update ui in onPostExecute. Or use runOnUiThread which is a method of activity class. or show dialog in onProgressUpdate(Progress...)

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

Also check the topic under Threads @ http://developer.android.com/guide/components/processes-and-threads.html

When an application is launched, the system creates a thread of execution for the application, called "main." This thread is very important because it is in charge of dispatching events to the appropriate user interface widgets, including drawing events. It is also the thread in which your application interacts with components from the Android UI toolkit (components from the android.widget and android.view packages). As such, the main thread is also sometimes called the UI thread.

Also use activity context

  alertDialog = new AlertDialog.Builder(ActivityContext).create();
Raghunandan
  • 132,755
  • 26
  • 225
  • 256
  • And how should I do it? I need to show a message in the end of everything..but I don't know which tasks have user chosen. – user2742861 Oct 21 '13 at 08:43
  • @user2742861 use the suggestion mentioned above – Raghunandan Oct 21 '13 at 08:45
  • I already know those events and I do use them. But see my second answer to Dhara Shah . – user2742861 Oct 21 '13 at 08:48
  • @user2742861 you can pass the selected item as a param to doinbackground. also why do you need asynctask and what do you intend to do in `doInbackground` ? I see you are only display a alertdialog – Raghunandan Oct 21 '13 at 08:49
  • Yes, I thought about AsyncTask because they are executed one by one. If I put in the end of the code "showMessage()" -> which is a simple void method, it will be executed immediately, it will not wait for the AsyncTasks to be completed. – user2742861 Oct 21 '13 at 08:51
  • you can use a handler for delay but i don't think you need asynctask for what you are doing. Pls read the links i posted in my post and then make a decision on whether to use asynctask or not – Raghunandan Oct 21 '13 at 08:53
  • @user2742861 then you need to pass the activity context to the constructor of asycntask and use the same there. and what is this `DownloadActivity.this` not activity context? – Raghunandan Oct 21 '13 at 09:04
  • It was something like you were telling me. Solved with the solution above. Thank you! - I will mark your help as correct. – user2742861 Oct 21 '13 at 09:12
  • 1
    @user2742861 you are welcome and do read the docs it will help you in the future – Raghunandan Oct 21 '13 at 09:13
  • the problem is that people voted my topic so bad I don't know why. I explain everything right, with code and quotes. Now I'm banned from creating another topics. – user2742861 Oct 21 '13 at 09:20
  • @user2742861 you can answer few questions and gain reputation and you can get your ban revoked or you can improve other questions posted. Your questions does not contain code related to check boxes and may adding few more details was needed. you talk about show message where is that code. for more help http://meta.stackoverflow.com/ – Raghunandan Oct 21 '13 at 09:44
3

you cannot call an alert box inside do inbackground method.same for a toast. No UI operations can be performed inside a doinbg method. instead use the post execute method, or change the way things have to be done.

  • And how should I do it? I need to show a message in the end of everything..but I don't know which tasks have user chosen. – user2742861 Oct 21 '13 at 08:43
  • make the user select the items first. And then perform the operations, thats the only way you can do it :) – Rat-a-tat-a-tat Ratatouille Oct 21 '13 at 08:45
  • Ah? That's is being already done. User select the items, the tasks begin. But how to you know which one is the last so you can show a message? – user2742861 Oct 21 '13 at 08:47
  • i am afraid but it would not be possible for you to show a message when a process is going on in a doinbg method. You could search on progressUpdate methd if that could help. But this way, nopes. Unless to simply show a message at the end of it all :).. – Rat-a-tat-a-tat Ratatouille Oct 21 '13 at 08:50
  • Dude, that's what I'm trying to tell you. I can't show a "simple" message in end of all, because 1º AsyncTask doesn't work with alertDialog ; 2º a simple Method to call 'Message' it will run even if the tasks aren't done yet. – user2742861 Oct 21 '13 at 09:00
  • are all the tasks performed in this async ?? keep track of all the items selected. and also of the items that have been performed. Check the counter of those performed and those remaining, and inside an if condition show the message box to the user in the onpost execute method. – Rat-a-tat-a-tat Ratatouille Oct 21 '13 at 09:09
1

you can access ui by this method inside the function 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));
    }
});

this is a snipped taken from my code which displays the downnloaded items.

Tunaki
  • 132,869
  • 46
  • 340
  • 423
Alp Altunel
  • 3,324
  • 1
  • 26
  • 27
0

In general in Java, when you call a thread B from another thread A 3 things happens

  1. onPreExecute : this method belongs to thread A (The caller thread)
  2. doInBackground : this method belongs to thread B (Make some work here)
  3. onPostExecute : this method belongs to thread A (The caller again)

Then, if you want to show an alert showing some result from the thread B YOU MUST do it in onPostExecute method because it belongs to thread A.

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

And remember, the method showDialogForResult can be part of the class in thread A.

Yury Euceda
  • 570
  • 4
  • 15