9.2.4 使用 AsyncTask异步
不过为了更加方便咱们在子线程中对 UI 进行操做,Android 还提供了另一些好用的工 具,AsyncTask 就是其中之一。借助 AsyncTask,即便你对异步消息处理机制彻底不了解, 也能够十分简单地从子线程切换到主线程。固然,AsyncTask 背后的实现原理也是基于异步 消息处理机制的,只是 Android 帮咱们作了很好的封装而已。ide
首先来看一下 AsyncTask 的基本用法,因为 AsyncTask 是一个抽象类,因此若是咱们想 使用它,就必需要建立一个子类去继承它。在继承时咱们能够为 AsyncTask 类指定三个泛型 参数,这三个参数的用途以下。线程
1. Params继承
在执行 AsyncTask 时须要传入的参数,可用于在后台任务中使用。io
2. Progressast
后台任务执行时,若是须要在界面上显示当前的进度,则使用这里指定的泛型做为 进度单位。class
3. Result后台
当任务执行完毕后,若是须要对结果进行返回,则使用这里指定的泛型做为返回值 类型。泛型
所以,一个最简单的自定义 AsyncTask 就能够写成以下方式:变量
class DownloadTask extends AsyncTask<Void, Integer, Boolean> {
……
}
这里咱们把 AsyncTask 的第一个泛型参数指定为 Void,表示在执行 AsyncTask 的时候不 须要传入参数给后台任务。第二个泛型参数指定为 Integer,表示使用整型数据来做为进度显 示单位。第三个泛型参数指定为 Boolean,则表示使用布尔型数据来反馈执行结果。
固然,目前咱们自定义的 DownloadTask 仍是一个空任务,并不能进行任何实际的操做, 咱们还须要去重写 AsyncTask 中的几个方法才能完成对任务的定制。常常须要去重写的方法 有如下四个。
1. onPreExecute()
这个方法会在后台任务开始执行以前调用,用于进行一些界面上的初始化操做,比 如显示一个进度条对话框等。
2. doInBackground(Params...)
这个方法中的全部代码都会在子线程中运行,咱们应该在这里去处理全部的耗时任 务。任务一旦完成就能够经过 return 语句来将任务的执行结果返回,若是 AsyncTask 的 第三个泛型参数指定的是 Void,就能够不返回任务执行结果。注意,在这个方法中是不 能够进行 UI 操做的,若是须要更新 UI 元素,好比说反馈当前任务的执行进度,能够调 用 publishProgress(Progress...)方法来完成。
3. onProgressUpdate(Progress...)
当在后台任务中调用了 publishProgress(Progress...)方法后,这个方法就会很快被调 用,方法中携带的参数就是在后台任务中传递过来的。在这个方法中能够对 UI 进行操 做,利用参数中的数值就能够对界面元素进行相应地更新。
4. onPostExecute(Result)
当后台任务执行完毕并经过 return 语句进行返回时,这个方法就很快会被调用。返 回的数据会做为参数传递到此方法中,能够利用返回的数据来进行一些 UI 操做,好比 说提醒任务执行的结果,以及关闭掉进度条对话框等。
所以,一个比较完整的自定义 AsyncTask 就能够写成以下方式:
class DownloadTask extends AsyncTask<Void, Integer, Boolean> {
@Override
protected void onPreExecute() {
progressDialog.show(); // 显示进度对话框
}
@Override
protected Boolean doInBackground(Void... params) {
try {
while (true) {
int downloadPercent = doDownload(); // 这是一个虚构的方法
publishProgress(downloadPercent);
if (downloadPercent >= 100) {
break;
}
}
} catch (Exception e) {
return false;
}
return true;
}
@Override
protected void onProgressUpdate(Integer... values) {
// 在这里更新下载进度
progressDialog.setMessage("Downloaded " + values[0] + "%");
}
@Override
protected void onPostExecute(Boolean result) {
progressDialog.dismiss(); // 关闭进度对话框
// 在这里提示下载结果
if (result) {
Toast.makeText(context, "Download succeeded", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(context, " Download failed", Toast.LENGTH_SHORT).show();
}
}
}
在这个 DownloadTask 中,咱们在 doInBackground()方法里去执行具体的下载任务。这个方法里的代码都是在子线程中运行的,于是不会影响到主线程的运行。注意这里虚构了一个 doDownload()方法,这个方法用于计算当前的下载进度并返回,咱们假设这个方法已经存在 了 。 在 得 到 了 当 前 的 下 载 进 度 后 , 下 面 就 该 考 虑 如 何 把 它 显 示 到 界 面 上 了 , 由 于 doInBackground()方法是在子线程中运行的,在这里确定不能进行 UI 操做,因此咱们能够调 用 publishProgress()方法并将当前的下载进度传进来,这样 onProgressUpdate()方法就会很快 被调用,在这里就能够进行 UI 操做了。
当下载完成后,doInBackground()方法会返回一个布尔型变量,这样 onPostExecute()方 法就会很快被调用,这个方法也是在主线程中运行的。而后在这里咱们会根据下载的结果来 弹出相应的 Toast 提示,从而完成整个 DownloadTask 任务。
简单来讲,使用 AsyncTask 的诀窍就是,在 doInBackground()方法中去执行具体的耗时 任务,在 onProgressUpdate()方法中进行 UI 操做,在 onPostExecute()方法中执行一些任务的 收尾工做。
若是想要启动这个任务,只需编写如下代码便可:
new DownloadTask().execute();
以上就是 AsyncTask 的基本用法,怎么样,是否是感受简单方便了许多?咱们并不须要 去考虑什么异步消息处理机制,也不须要专门使用一个 Handler 来发送和接收消息,只须要 调用一下 publishProgress()方法就能够轻松地从子线程切换到 UI 线程了。