这篇文章用来记录Android提供的轻量级异步类AsyncTask,文章分为一下几个章节:
①什么是AsyncTask?
AsyncTask是Android提供的轻量级的异步任务类,它本质上是是一个封装了Handle和线程池的异步框架。通过AsyncTask可以更加方便的执行后台任务以及更新UI。
但是,AsyncTask并不适合执行特别耗时的操作,特别耗时的操作建议使用线程池。
AsyncTask的内部封装了两个线程池(SerialExecutor和THREAD_POOL_EXECUTOR)和一个Handler(InternalHandler)。其中SerialExecutor线程池用于任务的排队,让需要执行的多个耗时任务,按顺序排列,THREAD_POOL_EXECUTOR线程池才真正地执行任务,InternalHandler用于从工作线程切换到主线程。
② AsyncTask的使用方式
AsyncTask的使用方式就涉及到三个参数,五个方法
1.三个参数
AsyncTask的类声明如下:
public abstract class AsyncTask
AsyncTask是一个泛型抽象类,有三个泛型参数,三个泛型类型参数的含义如下:
Params: 开始异步任务执行时传入的参数类型;
Progress:异步任务执行过程中,返回进度值的类型;
Result: 异步任务执行完成后,返回的结果类型;
如果AsyncTask确定不需要传递具体参数,那么这三个泛型参数可以用Void来代替。
2.五个AsyncTask的核心方法:
onPreExecute():该方法在主线程中执行,在异步任务执行之前调用,一般用于做一些初始化操作,准备工作(如展示一个进度条等);
doInBackground(Params…):在线程池中执行,此方法用于执行异步任务,其结果返回给onPostExecute(Result)方法。在此方法中调用publishProgress(),会调用onProgressUpdate(Progress…);
onProgressUpdate(Progress…): 在主线程中执行,当任务进度发生变化时该方法被调用,
onPostExecute(Result):主线程中执行,result是doInBackground(Params…)的返回值;
onCancelled();同样在主线程中执行,当异步任务被取消时,onCancelled()会被调用,这时,onPostExecute不会被调用;
AsyncTask的简单使用:
class DownloadTask extends AsyncTask {
@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("当前下载进度:" + values[0] + "%");
}
@Override
protected void onPostExecute(Boolean result) {
progressDialog.dismiss();
if (result) {
Toast.makeText(context, "下载成功", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(context, "下载失败", Toast.LENGTH_SHORT).show();
}
}
}
接着调用new DownloadTask().execute();
开启该异步任务。
上述代码比较简单,在doInBackground中执行下载任务,结果返回给onPostExecute来提示任务的执行结果。
③AsyncTask的内部原理
这里就不深入源码来进行解析了,本人水平不够,只根据《Android开发艺术探索》走了一遍,建议大家也可以更仔细的研读。
AsyncTask的内部封装了两个线程池(SerialExecutor和THREAD_POOL_EXECUTOR)和一个Handler(InternalHandler)。其中SerialExecutor线程池用于任务的排队,让需要执行的多个耗时任务,按顺序排列,THREAD_POOL_EXECUTOR线程池才真正地执行任务,InternalHandler用于从工作线程切换到主线程。
内部原理:
一:AsyncTask本质上是一个静态的线程池,它的派生子类 可以实现不同的异步任务,这些异步任务都提交到静态的线程中执行。
二:线程池中的工作线程执行doInBackground()方法来执行异步任务
三:当任务状态改变之后,工作线程会向主线程发送消息,AsyncTask内部的InternalHandler相应这些消息,并调用关的函数。
④AsyncTask的注意事项
1.异步任务的实例必须在UI线程中创建,即AsyncTask对象必须在UI线程中创建。
2.execute(Params… params)方法必须在UI线程中调用。
3.不要手动调用onPreExecute(),doInBackground(Params… params),onProgressUpdate(Progress… values),onPostExecute(Result result)这几个方法。
5.不能在doInBackground(Params… params)中更改UI组件的信息。
6.一个任务实例只能执行一次,如果执行第二次将会抛出异常。
AsyncTask使用不当的后果:
1.内存泄漏
如果AsyncTask被声明为Activity的非静态的内部类,那么AsyncTask会持有Activity的引用。如果Activity已经被销毁,AsyncTask的后台线程还在执行,它将继续在内存里保留这个引用,导致Activity无法被回收,引起内存泄露。
解决办法:将AsyncTask设为静态的;也可在静态Async内部持有外部Activity的弱引用去;可以在外部Activity的onDestory方法中即使取消AsyncTask。
2.生命周期
AsyncTask不与任何组件绑定生命周期,所以在Activity/或者Fragment中创建执行AsyncTask时,最好在Activity/Fragment的onDestory()调用 cancel(boolean);
3.结果丢失
屏幕旋转或Activity在后台被系统杀掉等情况会导致Activity的重新创建,之前运行的AsyncTask(非静态的内部类)会持有一个之前Activity的引用,这个引用已经无效,这时调用onPostExecute()再去更新界面将不再生效。
4.并行 or 串行
现在AsyncTask内部的任务是串行执行的,我们可以调用executeOnExector()
来让任务并行执行。O
以上内容总结自《Android开发艺术探索》,以及博客,慕课网实战课程。