一、概述
AsyncTask是一种轻量级的异步任务类,属于抽象类,使用时需实现子类和相关方法。它可以在线程池中执行后台任务,然后把执行的进度和最终结果传递给主线程并在主线程中更新UI,通过AsyncTask可以更加方便执行后台任务以及在主线程中操作UI,可以轻松解决多线程之间的通信问题,但是AsyncTask并不适合进行特别耗时的后台任务,对于特别耗时的任务来说,建议使用线程池。
二、作用
1、 实现多线程:在工作线程中执行任务,如耗时任务。
2、 异步通信、消息传递:实现工作线程&主线程(UI线程)之间的通信,即:将工作线程的执行结果传递给主线程,从而在主线程中执行相关的UI操作,最终保证线程安全。
三、优点
1、 方便实现异步通信:不需使用 “任务线程(如继承Thread类)+ Handler”的复杂组合。
2、 节省资源:采用线程池的缓存线程 + 复用线程,避免了频繁创建&销毁线程所带来的系统资源开销。
四、核心方法
要掌握AsyncTask,就要掌握三个参数和四个步骤。
1、三个参数
AsyncTask<Params, Progress, Result>
Params:表示异步任务执行时的参数类型,该参数会传给AysncTask的doInBackground()方法
Progress:表示异步任务的执行进度的参数类型,该参数会作为onProgressUpdate()方法的参数
Result:表示异步任务的返回结果的参数类型,该参数会作为onPostExecute()方法的参数
在定义一个类继承AsyncTask类的时候,必须指定好这三个泛型的类型,如果都不指定的话,则都将其写成Void,例如:
AsyncTask <Void, Void, Void>
2、四个步骤
当执行一个异步任务时,需要按照下面的4个步骤分别执行:
onPreExecute():这个方法是在执行异步任务之前的时候执行,并且是在UI Thread当中执行的, 通常我们在这个方法里做一些UI控件的初始化的操作,例如弹出ProgressDialog。
doInBackground(Params…params):在onPreExecute()方法执行完后,会马上执行这个方法,这个方法就是来处理异步任务的方法,Android操作系统会在后台的线程池当中开启一个worker thread来执行 这个方法(即在worker thread当中执行),执行完后将执行结果发送给最后一个onPostExecute方法,在这个方法里,我们可以从网络当中获取数据等一些耗时的操作。
onProgressUpdate(Progess…values):这个方法也是在UIThread当中执行的,在异步任务执行的时候,有时需要将执行的进度返回给UI界面,例如下载一张网络图片,我们需要时刻显示其下载的进度,就可以使用这个方法来更新进度。这个方法在调用之前,我们需要在doInBackground方法中调用一个 publishProgress(Progress) 的方法来将进度时时刻刻传递给onProgressUpdate方法来更新。
onPostExecute(Result…result):当异步任务执行完之后,就会将结果返回给这个方法,这个方法也是在UI Thread当中调用的,我们可以将返回的结果显示在UI控件上。
3、额外补充doInBackground和onCancelled
(1)为什么AsyncTask抽象类只有一个doInBackground的抽象方法呢?
如果要做一个异步任务,我们必须要为其开辟一个新的Thread,让其完成一些操作,而在完成这个异步任务时,可能并不需要弹出ProgressDialog,并不需要随时更新ProgressDialog的进度条,也并不需要将结果更新给UI界面,所以除了doInBackground方法之外的三个方法,都不是必须有的,因此必须要实现的方法是doInBackground方法。
(2)Cancel a Task-取消异步任务
onCancelled()在异步任务被取消时回调,可以在任何时刻来取消异步任务的执行,通过调用cancel(boolean)方法,调用完这个方法后系统会随后调用isCancelled()方法并且返回true。如果调用了这个方法,那么在doInBackgroud()方法执行完之后,就不会调用onPostExecute()方法了,取而代之的是调用onCancelled()方法。如果有必要的话,为了确保Task已经被取消了,需要经常调用isCancelled()方法来判断。
五、基本使用
AsyncTask的使用步骤分为两步:
- 第一步:创建AsyncTask子类 & 根据需求实现核心方法
- 第二步:创建AsyncTask子类的实例对象,手动调用execute()执行异步线程任务
第一步:创建AsyncTask子类
1、继承AsyncTask类
2、为3个泛型参数指定类型;若不使用,可用java.lang.Void类型代替
3、根据需求,在AsyncTask子类内实现核心方法
private class MyTask extends AsyncTask<Params, Progress, Result> {
//执行线程任务前的操作
@Override
protected void onPreExecute() {
...
}
//接收输入参数、执行任务中的耗时操作、返回线程任务执行的结果
@Override
protected String doInBackground(String... params) {
//自定义的线程任务
HttpClient httpClient = new DefaultHttpClient() ;
....
//可调用publishProgress()显示进度, 之后将执行onProgressUpdate()
publishProgress(count);
}
//在主线程 显示线程任务执行的进度
@Override
protected void onProgressUpdate(Integer... progresses) {
...
}
//接收线程任务执行结果、将执行结果显示到UI组件
@Override
protected void onPostExecute(String result) {
// UI操作
.....
}
//将异步任务设置为:取消状态
@Override
protected void onCancelled() {
...
}
}
第二步:创建AsyncTask子类的实例对象,手动调用execute(Params... params) 从而执行异步线程任务
MyTask mTask = new MyTask();
mTask.execute();
六、使用时注意事项
1、使用AsyncTask遵循的原则
(1)AsyncTask子类的实例必须在UI线程中创建
(2)execute方法必须在UI线程中调用
(3)同一个AsyncTask实例对象只能执行1次,若执行第2次将会抛出异常
(4)执行任务中,系统会自动调用AsyncTask的一系列方法:onPreExecute()、doInBackground()、onProgressUpdate() 、 onPostExecute() 不能手动调用这些方法
2、AsyncTask引起的内存泄漏
原因:非静态内部类持有外部类的匿名引用,导致Activity无法释放
解决: AsyncTask内部持有外部Activity的弱引用 & AsyncTask改为静态内部类 & 在Activity销毁之前,AsyncTask.cancel()取消运行,以此来保证程序的稳定
七、总结
本文介绍了AysncTask的基本使用和使用过程中注意事项,包括遵守原则和内存泄漏。稍后会分析AysncTask的工作原理,包括多任务时AysncTask采用的是串行or并行以及源码分析。