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