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

Does onPreExecute() and onPostExecute() execute on the UI thread or on the thread from which the AsyncTask has been started?

我已经在 android 中编写 AsyncTask 的简短后台操作已有一段时间了,并且有一个非常基本的问题。如果我从一个单独的线程而不是主 UI 线程启动一个 AsyncTask,我的 onPreExecute()onPostExecute 方法是否仍会在 UI 线程中调用或我从中启动 AsyncTask 的线程。我很好奇,因为当我从其他线程启动它时,我无法在 onPreExecute() 方法中显示弹出窗口。

编辑 2

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

作为堆栈跟踪中的行之一。

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

引用官方文档:

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)

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

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

的线程中

onPostExecute() 总是在主线程中运行。 (它是从 finish() 调用的,这发生在 Handler 内部,它使用主线程的循环程序)。