基本用法
在 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
。
請注意,你不能將原始型別(即 int
,float
和其他 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 都可以更好地完成工作。