onPreExecute()和onPostExecute()方法在UI线程上执行还是在AsyncTask启动的线程上执行?

11
我已经写了一段时间的AsyncTask来处理Android中的短后台操作,但是有一个非常基本的问题。如果我从另一个线程而不是主UI线程启动AsyncTask,那么我的onPreExecute()onPostExecute方法会在UI线程还是我启动AsyncTask的线程中被调用?我很好奇,因为当我从其他线程启动它时,无法在onPreExecute()方法中显示弹出窗口。
I tried writing this simple activity to try:

    public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        new Thread(new Runnable() {
            @Override
            public void run() {
                final TestAsyncTask task = new TestAsyncTask();
                task.execute();
            }
        }).start();
    }

    private class TestAsyncTask extends AsyncTask<Void, Void, Void> {

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }

        @Override
        protected Void doInBackground(Void... voids) {
            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            super.onPostExecute(aVoid);
            Toast.makeText(MainActivity.this, "Yo!", Toast.LENGTH_LONG).show();
        }
    }
}

这个运行得非常好。

但是当我用以下的代码来运行应用程序:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        new Thread(new Runnable() {
            @Override
            public void run() {
                final TestAsyncTask task = new TestAsyncTask();
                task.execute();
            }
        }).start();
    }

    private class TestAsyncTask extends AsyncTask<Void, Void, Void> {

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            Toast.makeText(MainActivity.this, "Yo!", Toast.LENGTH_LONG).show();
        }

        @Override
        protected Void doInBackground(Void... voids) {
            return null;
        }
    }
}

它出现了以下错误:
Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()

作为堆栈跟踪中的一行。

在Activity或Class中调用AssynTask? - Mohammad nabil
3个回答

16

虽然文档说这些回调在主线程中执行-但事实并非如此。onPreExecute()executeOnExecutor() 同步运行,也就是在启动 AsyncTask 的线程中运行。

onPostExecute() 总是在主线程中运行。(它是从 finish() 调用的,并且这会在使用主线程轮询器的 Handler 中发生。)


1
我尝试在onPreExecute()和onPostExecute()中制作Toast消息(我编辑了问题以包括代码)。在这两种情况下都失败了。 - Swapnil
@Swapnil,实际上你的代码从doInBackground()抛出了Toast。你确定从onPostExecute()中的Toast会导致应用程序崩溃吗? - Sergio
1
有人知道如何与Android团队沟通,以便我们也可以在文档中包含这个内容吗? - Swapnil

4

您应该在AsyncTask的onPostExecute()方法中进行UI更新,并显示警报或弹出窗口,该方法在UI线程上运行。AsyncTask的doinBackground()方法在另一个线程上运行。


1

引用官方文档:

onPostExecute
Added in API level 3
void onPostExecute (Result result)
Runs on the UI thread after doInBackground(Params...). The specified result is the value returned by doInBackground(Params...).


onPreExecute
Added in API level 3
void onPreExecute ()
Runs on the UI thread before doInBackground(Params...).

你可以在这里找到它 https://developer.android.com/reference/android/os/AsyncTask.html#onPostExecute(Result)

DoInBackground 在后台线程上运行,而 OnPreExecute 和 OnPostExecute 在主 Ui 线程上运行。


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