基本用法

在 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 都可以更好地完成工作。