AsyncTask:异步任务
多线程开发在Android中很常见,网络请求,图片加载,JSON解析等等。而且Android也提供了非常丰富的多线程方法,Thread、Runnable、Handler等等。
AsyncTask更进一步做了封装,直接开启一个任务,内部在子线程中处理耗时任务。还能在UI线程中更新界面。关于AsyncTask的原理参考《源码颇析AsyncTask工作原理》。
1、AsyncTask类
AsyncTask内部已经做了大量的封装,是一个抽象类。
1.1、doInBackground()
AsyncTask只有一个抽象方法doInBackground()。该方法返回的类型是泛型Result,定义AsyncTask时指定的返回结果类型。参数就是调用AsyncTask.execute(...)所传入的参数params。后面再详细的说明。
protected abstract Result doInBackground(Params... params);方法名就可以看出来这个方法是运行在后台子线程中,专门用来执行耗时任务的,官方文档的说明是:
/*
* 重写此方法以在后台线程上执行计算。 指定的参数是此任务的调用者传递给{@link #execute}的参数。
*
* 这部分代码将会运行在后台线程中.
* 为了更好的支持测试框架,推荐在前台(UI线程)调用execute()方法。
*
* 可以在该方法中调用{@link #publishProgress}去更新U进度,
* 上面的方法会择机调用onProgressUpdate,可以在其中去更新UI界面上的进度
*/1.2、重写方法
继承AsyncTask自定义自己的异步任务,除了实现唯一的抽象方法doInBackground(),一般还需要重写其它几个重要的方法:onPreExecute()、onPostExecute()、onProgressUpdate()。
public class TaskAsyncTask extends AsyncTask<String, Integer, Boolean> {
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected Boolean doInBackground(String[] objects) {
return null;
}
@Override
protected void onPostExecute(Boolean o) {
super.onPostExecute(o);
}
@Override
protected void onProgressUpdate(Integer[] values) {
super.onProgressUpdate(values);
}
}1.3、其它方法
此外还有几个方法:onCancle(Boolean )、onCancle()。取消任务,最好在生命周期的onDestory()调用,取消后台任务的执行。
/**
* <p>Runs on the UI thread after {@link #cancel(boolean)} is invoked and
* {@link #doInBackground(Object[])} has finished.</p>
*
* <p>The default implementation simply invokes {@link #onCancelled()} and
* ignores the result. If you write your own implementation, do not call
* <code>super.onCancelled(result)</code>.</p>
*
* @param result The result, if any, computed in
* {@link #doInBackground(Object[])}, can be nul
*/
@SuppressWarnings({"UnusedParameters"})
@MainThread
protected void onCancelled(Result result) {
onCancelled();
}这些方法根据业务需求,按需重写。按照AsyncTask内部设定的顺序依次执行。
2、AsyncTask中的泛型
AsyncTask中有三个泛型,第一个泛型是传入参数的类型Params,第二个泛型是任务执行的进度Progress,一般为Integer或者Void;第三个泛型是任务执行的结果Result,可以为Boolean值表示是否执行成功,也可以是Bitmap等获取的数据。
public abstract class AsyncTask<Params, Progress, Result> {
... ...
}注意:三个泛型不能为基本数据类型,要是是int就用Integer,bool就用Boolean,void就用Void类型,使用包装器类型替代基本类型。
2.1、方法中的泛型参数
仔细看可以看到前面几个方法的参数和返回值与这几个泛型密切相关。
doInBackground()传入的参数类型是第一个泛型Params,该类型也是AsyncTask的execute()方法的参数类型。返回结果类型是第三个泛型Result
@Override
protected Boolean doInBackground(String[] objects) {
return null;
}onPostExecute()方法在执行完后台任务doInBackground()之后执行,发布执行结果,方法参数就是第三个泛型Result。这里定义的是Boolean类型。
@Override
protected void onPostExecute(Boolean o) {
super.onPostExecute(o);
}onProgressUpdate()方法的参数类型是第二个泛型Progress,任务执行的进度,一般为Integer表示下载进度等。或者直接为Void类型,不需要知道进度。
@Override
protected void onProgressUpdate(Integer[] values) {
super.onProgressUpdate(values);
}3、创建AsyncTask
继承AsyncTask的类提供构造方法,可以有默认的无参构造函数:
AsyncTask asyncTask = new TaskAsyncTask();一般还会通过有参构造函数传入一些数据,初始化AsyncTask中的成员变量。比如从Activity中传入一个回调接口,用于在onPostExecute()、onProgressUpdate()中调用更新数据。
AsyncTask asyncTask = new TaskAsyncTask(listener);4、执行AsyncTask
创建好AsyncTask对象之后,就可以开始执行任务了,有两种执行方法供调用。
4.1、execute()
直接调用execute()
asyncTask.execute();使用该种方法使用的是默认线程池,查看源码可以发现,内部调用的是第二种方法,只不过传入的线程池是默认的AsyncTask.SERIAL_EXECUTOR
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}而这个AsyncTask中的sDefaultExecutor定义如下:
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
...
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();4.2、executeOnExecutor()
指定线程池执行任务,AsyncTask中默认定义了两种线程池:
①SERIAL_EXECUTOR中的任务按照“先进先执行,依次执行”的原则,后续任务要等先前的任务执行完毕后才会执行,顺次执行。也是默认的执行器。
asyncTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, params...);②THREAD_POOL_EXECUTOR被加入线程池的任务会立刻执行,也就是所有任务并发执行。
asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params...);但是有个前提,THREAD_POOL_EXECUTOR中一起执行的任务超过了线程池数量个,那么新加入的任务会等线程执行完毕了再执行。这个线程池最大定义目前是20,查看以前的博客的文档说的是(CPU*2+1)。在AsyncTask类静态初始化:
private static final int CORE_POOL_SIZE = 1;
private static final int MAXIMUM_POOL_SIZE = 20;
private static final int BACKUP_POOL_SIZE = 5;
private static final int KEEP_ALIVE_SECONDS = 3;
...
static {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(), sThreadFactory);
threadPoolExecutor.setRejectedExecutionHandler(sRunOnSerialPolicy);
THREAD_POOL_EXECUTOR = threadPoolExecutor;
}5、AsyncTask注意点
①Task的实例必须在UI线程中创建
②execute方法必须在UI线程中调用
③不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params…), onProgressUpdate(Progress…)这几个方法
④该task只能被执行一次,否则多次调用时将会出现异常
⑤AsyncTask不与任何组件绑定生命周期。使用建议:在Activity 或 Fragment中使用 AsyncTask时,最好在Activity 或 Fragment的onDestory()调用 cancel(boolean);
⑥AsyncTask应被声明为Activity的静态内部类。或者单独继承AsyncTask定义一个类。否则,当Activity需销毁时,会因AsyncTask保留对Activity的引用 而导致Activity无法被回收,最终引起内存泄露。
参考博客:
别再傻傻得认为AsyncTask只可以在主线程中创建实例和调用execute方法


