Jules Hummelink
Jules Hummelink

Reputation: 674

Problems with AsyncTasks?

I have a problem with AsyncTasks. I have this in onCreate()

new ProgressTask().execute();

And this is my Task:

private class ProgressTask extends AsyncTask<String, Integer, Boolean> {
    private ProgressDialog dialog;
    public ProgressTask() {
        //dialog = new ProgressDialog(getBaseContext());
    }



    /** progress dialog to show user that the backup is processing. */

    /** application context. */
    private Context context;

    protected void onPreExecute() {
        dialog = new ProgressDialog(getBaseContext());
        dialog.setTitle("Loading connection...");
        dialog.setMessage("Loading...");
        dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        dialog.setMax(100);
        dialog.setProgress(0);
        dialog.show();
    }

    @Override
    protected void onPostExecute(final Boolean success) {
        if (dialog.isShowing()) {
            dialog.dismiss();
        }

        if (success) {
            Toast.makeText(context, "OK", Toast.LENGTH_LONG).show();
        } else {
            Toast.makeText(context, "Error", Toast.LENGTH_LONG).show();
        }
    }

    protected Boolean doInBackground(final String... args) {
        try{
            //Get device ID
            publishProgress(0);
            loading.setMessage("Getting device ID...");
            try {
                getDeviceId();
            } catch (Exception ex) {
                ErrorMessage("Couldn't get device ID");
                ErrorAlert += "Error 101: Couldn't get device ID\n";
            }
            Thread.sleep(2000);
            publishProgress(20);

            //Open connection
            loading.setMessage("Opening connection...");
            try {
                openConnection();
            } catch (IOException ex) {
                ErrorMessage("Couldn't open connection");
                ErrorAlert += "Error 102: Couldn't open connection\n";
            }
            Thread.sleep(2000);
            publishProgress(40);

            //Testing connection
            loading.setMessage("Testing connection...");
            if (!mmSocket.isConnected()) {
                ErrorMessage("Test failed!");
                ErrorAlert += "Error 103: Test failed!\n";
            }
            Thread.sleep(2000);
            publishProgress(60);

            //Calibrate sensors
            loading.setMessage("Calibrating sensors...");
            try {
                sendCommand("c");
            } catch (IOException ex) {
                ErrorMessage("Couldn't calibrate sensors");
                ErrorAlert += "Error 104: Couldn't calibrate sensors\n";
            }
            Thread.sleep(2000);
            publishProgress(80);

            //Finish
            loading.setMessage("Finishing...");
            Thread.sleep(1000);
            publishProgress(90);

            //Clear
            loading.setMessage("Clearing some stuff...");
            Thread.sleep(1000);
            publishProgress(100);

            return true;
        } catch (Exception e){

            return false;
        }
    }

    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values[0]);
        dialog.setProgress(values[0]);
    }


}

But when I launch the activity, the app stops :(

This is the output:

03-06 12:32:35.902 10648-10648/com.jules_citronic.racecarcontrol E/AndroidRuntime: FATAL EXCEPTION: main
                                                                               Process: com.jules_citronic.racecarcontrol, PID: 10648
                                                                               Theme: themes:{default=overlay:theme.lonecm12.kikkosart.com.lonecm12, iconPack:theme.lonecm12.kikkosart.com.lonecm12, fontPkg:theme.lonecm12.kikkosart.com.lonecm12, com.android.systemui=overlay:theme.lonecm12.kikkosart.com.lonecm12, com.android.systemui.navbar=overlay:theme.lonecm12.kikkosart.com.lonecm12}
                                                                               java.lang.RuntimeException: Unable to start activity ComponentInfo{com.jules_citronic.racecarcontrol/com.jules_citronic.racecarcontrol.control}: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
                                                                                   at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2450)
                                                                                   at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2520)
                                                                                   at android.app.ActivityThread.-wrap11(ActivityThread.java)
                                                                                   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1363)
                                                                                   at android.os.Handler.dispatchMessage(Handler.java:102)
                                                                                   at android.os.Looper.loop(Looper.java:148)
                                                                                   at android.app.ActivityThread.main(ActivityThread.java:5466)
                                                                                   at java.lang.reflect.Method.invoke(Native Method)
                                                                                   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
                                                                                   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
                                                                                Caused by: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
                                                                                   at android.view.ViewRootImpl.setView(ViewRootImpl.java:571)
                                                                                   at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:310)
                                                                                   at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:86)
                                                                                   at android.app.Dialog.show(Dialog.java:319)
                                                                                   at com.jules_citronic.racecarcontrol.control$ProgressTask.onPreExecute(control.java:109)
                                                                                   at android.os.AsyncTask.executeOnExecutor(AsyncTask.java:604)
                                                                                   at android.os.AsyncTask.execute(AsyncTask.java:551)
                                                                                   at com.jules_citronic.racecarcontrol.control.onCreate(control.java:84)
                                                                                   at android.app.Activity.performCreate(Activity.java:6251)
                                                                                   at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1108)
                                                                                   at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2403)
                                                                                   at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2520) 
                                                                                   at android.app.ActivityThread.-wrap11(ActivityThread.java) 
                                                                                   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1363) 
                                                                                   at android.os.Handler.dispatchMessage(Handler.java:102) 
                                                                                   at android.os.Looper.loop(Looper.java:148) 
                                                                                   at android.app.ActivityThread.main(ActivityThread.java:5466) 
                                                                                   at java.lang.reflect.Method.invoke(Native Method) 
                                                                                   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) 
                                                                                   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 

I'm not so good with Threads and stuff so I hope that someone can help me.

EDIT: I changed getBaseContext to context and placed "context = control.this". by the way, control is the name of my activity/class. Now it launched the activity but never shows a ProgressDialog and doesn't connect to Bluetooth. It gives me a toast with "Error".

EDIT: The exception exports this:

03-06 13:09:04.858 15370-15535/com.jules_citronic.racecarcontrol E/MYAPP: exception
                                                                      java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
                                                                          at android.os.Handler.<init>(Handler.java:200)
                                                                          at android.os.Handler.<init>(Handler.java:114)
                                                                          at android.widget.Toast$TN.<init>(Toast.java:347)
                                                                          at android.widget.Toast.<init>(Toast.java:103)
                                                                          at android.widget.Toast.makeText(Toast.java:261)
                                                                          at com.jules_citronic.racecarcontrol.control.ErrorMessage(control.java:301)
                                                                          at com.jules_citronic.racecarcontrol.control$ProgressTask.doInBackground(control.java:135)
                                                                          at com.jules_citronic.racecarcontrol.control$ProgressTask.doInBackground(control.java:90)
                                                                          at android.os.AsyncTask$2.call(AsyncTask.java:295)
                                                                          at java.util.concurrent.FutureTask.run(FutureTask.java:237)
                                                                          at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
                                                                          at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
                                                                          at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
                                                                          at java.lang.Thread.run(Thread.java:818)

EDIT: It worked :). This is the final class:

private class ProgressTask extends AsyncTask<String, Integer, Boolean> {
    private ProgressDialog dialog;
    private Context context;
    public ProgressTask(Context context) {
        this.context = context;
        //dialog = new ProgressDialog(getBaseContext());
    }



    /** progress dialog to show user that the backup is processing. */

    /** application context. */

    protected void onPreExecute() {
        dialog = new ProgressDialog(context);
        dialog.setTitle("Loading connection...");
        dialog.setMessage("Loading...");
        dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        dialog.setMax(100);
        dialog.setProgress(0);
        dialog.show();
    }

    @Override
    protected void onPostExecute(final Boolean success) {
        if (dialog.isShowing()) {
            dialog.dismiss();
        }

        if (success) {
            Toast.makeText(context, "OK", Toast.LENGTH_LONG).show();
        } else {
            Toast.makeText(context, "Error", Toast.LENGTH_LONG).show();
        }
    }

    protected Boolean doInBackground(final String... args) {
        try {
            Looper.prepare();
        } catch (Exception ex) {
            Log.e("MYAPP", "Exception in looper " + ex.getMessage());
        }
        try{
            //Get device ID
            publishProgress(0);
            try {
                getDeviceId();
            } catch (Exception ex) {
                ErrorMessage("Couldn't get device ID");
                ErrorAlert += "Error 101: Couldn't get device ID\n";
            }
            Thread.sleep(2000);
            publishProgress(20);

            //Open connection
            try {
                openConnection();
            } catch (IOException ex) {
                ErrorMessage("Couldn't open connection");
                ErrorAlert += "Error 102: Couldn't open connection\n";
            }
            Thread.sleep(2000);
            publishProgress(40);

            //Testing connection
            if (!mmSocket.isConnected()) {
                ErrorMessage("Test failed!");
                ErrorAlert += "Error 103: Test failed!\n";
            }
            Thread.sleep(2000);
            publishProgress(60);

            //Calibrate sensors
            try {
                sendCommand("c");
            } catch (IOException ex) {
                ErrorMessage("Couldn't calibrate sensors");
                ErrorAlert += "Error 104: Couldn't calibrate sensors\n";
            }
            Thread.sleep(2000);
            publishProgress(80);

            //Finish
            Thread.sleep(1000);
            publishProgress(90);

            //Clear
            Thread.sleep(1000);
            publishProgress(100);

            return true;
        } catch (Exception e){
            Log.e("MYAPP", "exception", e);
            return false;
        }
    }

    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values[0]);
        dialog.setProgress(values[0]);

        if (values[0] == 0){
            dialog.setMessage("Getting device ID...");
        }
        if (values[0] == 20){
            dialog.setMessage("Opening connection...");
        }
        if (values[0] == 40){
            dialog.setMessage("Testing connection...");
        }
        if (values[0] == 60){
            dialog.setMessage("Calibrating sensors...");
        }
        if (values[0] == 80){
            dialog.setMessage("Finishing...");
        }
        if (values[0] == 90){
            dialog.setMessage("Clearing some stuff...");
        }
    }


}

Upvotes: 1

Views: 3367

Answers (4)

ELITE
ELITE

Reputation: 5940

add

try {
    Looper.prepare();
} catch (Exception ex) {
    Log.e(tag, "Exception in looper " + ex.getMessage());
}

these lines in doInBackground method. These lines should be at start of doInBackground method. I faced same exception then i tried these lines.

OR

Remove these lines from onPreExecute method and declare in constructor.

    dialog = new ProgressDialog(getBaseContext());
    dialog.setTitle("Loading connection...");
    dialog.setMessage("Loading...");
    dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
    dialog.setMax(100);
    dialog.setProgress(0);

And in onPreExecute method, use only dialog.show() method.

Hope it'll help you.

Refer this answer for more details

Upvotes: 0

Malcolm
Malcolm

Reputation: 41510

The posted exception indeed happens because your context is a base context and not an activity. However, I think this whole setup is not really correct.

The main problem with long-running tasks is that they may outlive the activity if it gets recreated for some reason (the most common is changing the device orientation). In that case you may end up calling methods of the activity which is already gone, and that will lead to exceptions and unexpected behavior.

I have previously left another answer which outlines how you can deal with this. In general, you can create a loader which handles the background work and sends back the objects representing the loaded data or the current state. The loader framework can automatically attach and detach to the activity so you always work with the active instance of it and avoid the problems.

Upvotes: 0

Kae10
Kae10

Reputation: 669

Change constructor and onPreExecute() method of your AsyncTask like this:

    public ProgressTask(Context c) {
        //dialog = new ProgressDialog(getBaseContext());
        context = c;
    }



    /** progress dialog to show user that the backup is processing. */

    /** application context. */
    private Context context;

    protected void onPreExecute() {
        dialog = new ProgressDialog(this.context);
        dialog.setTitle("Loading connection...");
        dialog.setMessage("Loading...");
        dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        dialog.setMax(100);
        dialog.setProgress(0);
        dialog.show();
    }

Then, try to create AsyncTask instance in your activity :

ProgressTask task = new ProgressTask(YourActivity.this);
task.execute();

Upvotes: 0

Julian Kron&#233;
Julian Kron&#233;

Reputation: 179

Since AsyncTask does not inherit from Context, it has no way of accessing the current context.

You have to pass the current context as a parameter to the constructor and set it there.

private Context context;
public ProgressTask(Context context) {
    this.context = context;
}

And then pass context from new ProgressTask(context).execute();

Upvotes: 1

Related Questions