基本用法

在 Android 活动服务中 ,大多数回调都在主线程上运行。这使得更新 UI 变得简单,但是在主线程上运行处理器或 I / O 繁重的任务可能会导致 UI 暂停并变得无响应( 关于当时发生的事情的官方文档 )。

你可以通过将这些较重的任务放在后台线程来解决此问题。

一种方法是使用 AsyncTask ,它提供了一个框架,以方便后台线程的使用,并在后台线程完成其工作之前,期间和之后执行 UI 线程任务。

扩展 AsyncTask 时可以覆盖的方法:

  • onPreExecute():在执行任务之前在 UI 线程上调用
  • doInBackground(): 在 onPreExecute() 完成执行后立即在后台线程上调用。
  • onProgressUpdate():在调用 publishProgress(Progress...) 后在 UI 线程上调用。
  • onPostExecute(): 在后台计算完成后在 UI 线程上调用

public class MyCustomAsyncTask extends AsyncTask<File, Void, String> {

    
    @Override
    protected void onPreExecute(){
        // This runs on the UI thread before the background thread executes.
        super.onPreExecute();
        // Do pre-thread tasks such as initializing variables. 
        Log.v("myBackgroundTask", "Starting Background Task");  
    }

    @Override
    protected String doInBackground(File... params) {
        // Disk-intensive work. This runs on a background thread.
        // Search through a file for the first line that contains "Hello", and return
        // that line.
        try (Scanner scanner = new Scanner(params[0])) {
            while (scanner.hasNextLine()) {
                final String line = scanner.nextLine();
                publishProgress(); // tell the UI thread we made progress

                if (line.contains("Hello")) {
                    return line;
                }
            }
            return null;
        }
    }

    @Override
    protected void onProgressUpdate(Void...p) {
        // Runs on the UI thread after publishProgress is invoked
        Log.v("Read another line!")
    }        

    @Override
    protected void onPostExecute(String s) {
        // This runs on the UI thread after complete execution of the doInBackground() method
        // This function receives result(String s) returned from the doInBackground() method.
        // Update UI with the found string.
        TextView view = (TextView) findViewById(R.id.found_string);
        if (s != null) {
            view.setText(s);
        } else {
            view.setText("Match not found.");
        }
    }

}

用法:

MyCustomAsyncTask asyncTask = new MyCustomAsyncTask<File, Void, String>();
// Run the task with a user supplied filename.
asyncTask.execute(userSuppliedFilename);

或者干脆:

new MyCustomAsyncTask().execute(userSuppliedFilename);

注意

在定义 AsyncTask 时,我们可以在 < > 括号之间传递三种类型。
定义为 <Params, Progress, Result>(参见参数部分

在前面的例子中,我们使用了 <File, Void, String> 类型:

AsyncTask<File, Void, String>
// Params has type File
// Progress has unused type
// Result has type String

如果要将类型标记为未使用,则使用 Void

请注意,你不能将原始类型(即 intfloat 和其他 6 个)作为参数传递。在这种情况下,你应该传递他们的包装类 ,例如 Integer 而不是 int,或者 Float 而不是 float

AsyncTask 和 Activity 生命周期

AsyncTasks 不遵循 Activity 实例的生命周期。如果在 Activity 中启动 AsyncTask 并旋转设备,则将销毁 Activity 并创建新实例。但 AsyncTask 不会死。它会继续生存直到它完成。

解决方案:AsyncTaskLoader

Loaders 的一个子类是 AsyncTaskLoader。该类执行与 AsyncTask 相同的功能,但更好。它可以更轻松地处理 Activity 配置更改,并且它在 Fragments 和 Activities 的生命周期内运行。好消息是 AsyncTaskLoader 可以在任何使用 AsyncTask 的情况下使用。无论何时需要将数据加载到内存中以供 Activity / Fragment 处理,AsyncTaskLoader 都可以更好地完成工作。