AsyncTasks 有问题吗?

Problems with AsyncTasks?

我对 AsyncTasks 有疑问。 我在 onCreate()

中有这个
new ProgressTask().execute();

这是我的任务:

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


}

但是当我启动 activity 时,应用程序停止了 :(

这是输出:

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) 

我对 Threads 之类的东西不是很好所以我希望有人能帮助我。

编辑: 我将 getBaseContext 更改为上下文并放置 "context = control.this"。对了,control是我的activity/class的名字。现在它启动了 activity 但从未显示 ProgressDialog 并且未连接到蓝牙。它让我祝酒 "Error".

编辑: 异常导出这个:

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.call(AsyncTask.java:295)
                                                                          at java.util.concurrent.FutureTask.run(FutureTask.java:237)
                                                                          at android.os.AsyncTask$SerialExecutor.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)

编辑: 有效 :)。这是最后的 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...");
        }
    }


}

由于AsyncTask没有继承自Context,因此无法访问当前上下文。

您必须将当前上下文作为参数传递给构造函数并将其设置在那里。

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

然后从 new ProgressTask(context).execute();

传递上下文

像这样更改 AsyncTask 的构造函数和 onPreExecute() 方法:

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

然后,尝试在 activity 中创建 AsyncTask 实例:

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

发布的异常确实发生了,因为您的上下文是基本上下文而不是 activity。但是,我认为整个设置并不正确。

长运行 任务的主要问题是,如果由于某种原因(最常见的是更改设备方向)重新创建,它们的寿命可能比 activity 长。在这种情况下,您最终可能会调用已经消失的 activity 的方法,这将导致异常和意外行为。

我之前在 another answer 中概述了您可以如何处理这个问题。通常,您可以创建一个加载程序来处理后台工作并发回代表加载数据或当前状态的对象。加载器框架可以自动附加和分离 activity,因此您始终使用它的活动实例并避免出现问题。

添加

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

doInBackground 方法中的这些行。这些行应该在 doInBackground 方法的开头。我遇到了同样的异常然后我尝试了这些行。

onPreExecute 方法中删除这些行并在构造函数中声明。

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

并且在 onPreExecute 方法中,仅使用 dialog.show() 方法。

希望对您有所帮助。

参考this答案了解更多详情