概述:
AsyncTask是一个轻量级的异步任务类,在线程池中串行执行任务,通过Handler把进度和执行结果发送到主线程,更新UI。
简单使用:
MyAsyncTask mAsyncTask = new MyAsyncTask();
mAsyncTask.execute("params");
/**
* AsyncTask<Void, Integer, Boolean>
* 泛型参数分别为:后台任务执行的参数,更新进度的参数,任务执行完成的结果
*/
public class MyAsyncTask extends AsyncTask<String, Integer, Boolean>{
private ProgressDialog mProgress;
private int currentProgress;
//任务开始前的准备操作,可以做些UI的准备或初始化。
//多个任务时,无论是否等待,asyncTask.execute()的时候该方法就在主线程调用
@Override
protected void onPreExecute() {
super.onPreExecute();
mProgress.setMax(100);
mProgress.setMessage("下载进度");
mProgress.show();
}
/**
* 线程池中执行,不能更新UI
**/
@Override
protected Boolean doInBackground(String... params) {
while (currentProgress <= 100) {
//想更新进度的话,主动调用该方法,会通过handler给onProgressUpdate方法。
publishProgress(currentProgress);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
return false;
}
currentProgress++;
}
return true;
}
//publishProgress通过handler调用,主线程
@Override
protected void onProgressUpdate(Integer... values) {
mProgress.setMessage("下载进度:"+values[0]);
}
//执行完成后的结果,主线程
@Override
protected void onPostExecute(Boolean aBoolean) {
super.onPostExecute(aBoolean);
if (aBoolean) {
mProgress.setMessage("下载完成");
}else {
mProgress.setMessage("下载出错");
}
mProgress.cancel();
}
//中断任务时,调用该方法。但并不一定会马上中断。
@Override
protected void onCancelled() {
super.onCancelled();
}
}
源码分析:
AsyncTask内部使用的是Callable、Future,在线程池中执行的原理
构造函数入手:
初始化:主线程Handler、callable、future
public AsyncTask() {
// 主线程Handler
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
// Callable,AsyncTask任务在这里执行
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//后台要执行的任务
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
} finally {
//任务执行完以后,通过msg在Handler中调用onPostExecute
postResult(result);
}
return result;
}
};
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
try {
postResultIfNotInvoked(get());
} catch (InterruptedException e) {
android.util.Log.w(LOG_TAG, e);
} catch (ExecutionException e) {
throw new RuntimeException("An error occurred while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
}
调用mAsyncTask.execute()方法:
将mFuture封装到Runnable中,放入队列,在线程池中执行
多个AsyncTask时,依次从队列中取出,串行执行
方法1:
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
方法2:
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
//如果状态为正在运行或者已经结束,报错。只能调用一次mAsyncTask.execute()方法
if (mStatus != Status.PENDING) {
switch (mStatus) {
case RUNNING:
throw new IllegalStateException("Cannot execute task: the task is already running.");
case FINISHED:
throw new IllegalStateException("Cannot execute task: the task has already been executed "
+ "(a task can be executed only once)");
}
}
mStatus = Status.RUNNING;//改变状态
//此时还是在主线程中,所以可以操作UI
onPreExecute();
mWorker.mParams = params;
//Executor实现类
exec.execute(mFuture);
return this;
}
//上一步,将mFuture传入该类execute中
private static volatile Executor sDefaultExecutor = new SerialExecutor();
private static class SerialExecutor implements Executor {
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive;
//mFuture参数,也即是构造方法中的实例
public synchronized void execute(final Runnable r) {
//封装成一个Runnable,放到队列的最后。
语句1: mTasks.offer(new Runnable() {
public void run() {
try {
//mFuture的run方法,执行Callable.call(),即mWork.call,进而调用doInBackground()(初始化中实现)
语句5: r.run();
} finally {
语句6: scheduleNext();
}
}
});
//多个AsyncTask是串行执行:null时马上执行
//上面finally中执行完以后,自动取出下一个任务执行
if (mActive == null) {
语句2: scheduleNext();
}
}
protected synchronized void scheduleNext() {
//取出队列中的Runnable放入线程池中执行
语句3: if ((mActive = mTasks.poll()) != null) {
语句4: THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
到这以后,AsyncTask基本上执行流程就完了:
- 构造方法中初始化handler、Callable、future
- asycnTask.execute将任务封装到Future --> Runnable,放入队列中
- 如果线程池当前没有任务,马上执行。如果有正在执行的任务mActive,则等待执行完以后再从队列中取出执行
- onPostExecute、onProgressUpdate方法的调用通过给主线程mHandler发送消息调用,在源码中可以轻易找到
串行、并行
- 默认串行
- asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "")直接使用线程池,并行
//静态变量,线程池初始化
static {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
sPoolWorkQueue, sThreadFactory);
threadPoolExecutor.allowCoreThreadTimeOut(true);
THREAD_POOL_EXECUTOR = threadPoolExecutor;
}
//默认Executor实现类,串行
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static class SerialExecutor implements Executor {
//串行逻辑
}
//调用asyncTask方法,默认使用串行实现类
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
...
exec.execute(mFuture);
return this;
}
所以,直接调用asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "")
把future对象直接放入线程池中执行,并行
- 调用asyncTask.execute方法时,内部调用executeOnExecutor使用的是默认Executor实现类,决定了串行执行
- 我们可以调用asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, ""),直接使用线程池来处理,这样就可以并行执行了
- "AsyncTask并不适合进行特别耗时的后台任务,对特别耗时的任务,建议使用线程池。"--开发艺术探索
- 原因是因为:AsyncTask默认是串行执行的,如果是特别耗时任务,会影响其他AsyncTask任务迟迟得不到处理
- 如果是特别耗时任务时,可在后台服务、计划任务、线程池中处理
cancle操作
<!--AsyncTask-->
public final boolean cancel(boolean mayInterruptIfRunning) {
mCancelled.set(true);
return mFuture.cancel(mayInterruptIfRunning);
}
<!--FutureTask-->
public boolean cancel(boolean mayInterruptIfRunning) {
if (!(state == NEW &&
return false;
try { // in case call to interrupt throws exception
if (mayInterruptIfRunning) {
try {
Thread t = runner;
if (t != null) t.interrupt();
} finally { // final state
}
}
} finally {
finishCompletion();
}
return true;
}
//影响doInBackground以后调用哪个方法
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
- 不会立即中断任务
- 如果cancle时正在执行,影响doInBackground以后调用哪个方法
- 可在doInBackground中isCancelled或Thread.interrupted()判断来终止任务
- doInBackground可能会引起InterruptedException,需做收尾处理工作
内存泄漏
页面销毁时,doInBackground可能还未完成,内部类AsyncTask实例持有引用,造成内存泄漏。
GC Root是什么:
是root,不会被回收
- 运行中的线程
- 静态对象
- native code中的引用
所以,造成内存泄漏的原因实际上是因为“运行中的线程”是GC Root不会被回收。
- 其它类型的线程方案,如Thread、Executor、HandlerThread、IntentService都会有这样的问题
- AsyncTask并没有比其它线程方案更危险,需要单独强调
- 只要时间不长,没有必要做内存泄漏的处理
- 需要做的只是更新UI是判断一下Activity是否已被销毁