最近在总结Android线程优化相关的知识,顺便说说AsyncTask,这是个google出来很早的封装类,也是我们常用到的一个操作线程。接下来,让我们一起深入学习回顾它吧。
一、简单使用和介绍(会的同学可以直接跳过看源码分析)
-
看demo
//execute NumAsyncTask numAsyncTask = new NumAsyncTask(); numAsyncTask.execute(); ------------------------------------ private class NumAsyncTask extends AsyncTask<Void, Integer, Void>{ @Override protected Void doInBackground(Void... voids) { for (int i = 0; i < 8; i++) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } publishProgress(i); Log.e(TAG, "doInBackground : for -"+i+" "+Thread.currentThread().getName()); } return null; } @Override protected void onPreExecute() { super.onPreExecute(); Log.e(TAG, "onPreExecute : "+Thread.currentThread().getName()); } @Override protected void onPostExecute(Void aVoid) { super.onPostExecute(aVoid); Log.e(TAG, "onPostExecute : "+Thread.currentThread().getName()); } @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); Log.e(TAG, "onProgressUpdate : "+values[0]+" " +Thread.currentThread().getName()); } @Override protected void onCancelled() { super.onCancelled(); Log.e(TAG, "onCancelled : "+Thread.currentThread().getName()); } }
-
执行结果
$NumAsyncTask: onPreExecute : main $NumAsyncTask: doInBackground : for -0 AsyncTask #1 $NumAsyncTask: onProgressUpdate : 0 main $NumAsyncTask: doInBackground : for -1 AsyncTask #1 $NumAsyncTask: onProgressUpdate : 1 main $NumAsyncTask: doInBackground : for -2 AsyncTask #1 $NumAsyncTask: onProgressUpdate : 2 main $NumAsyncTask: doInBackground : for -3 AsyncTask #1 $NumAsyncTask: onProgressUpdate : 3 main $NumAsyncTask: doInBackground : for -4 AsyncTask #1 $NumAsyncTask: onProgressUpdate : 4 main $NumAsyncTask: doInBackground : for -5 AsyncTask #1 $NumAsyncTask: onProgressUpdate : 5 main $NumAsyncTask: doInBackground : for -6 AsyncTask #1 $NumAsyncTask: onProgressUpdate : 6 main $NumAsyncTask: doInBackground : for -7 AsyncTask #1 $NumAsyncTask: onProgressUpdate : 7 main $NumAsyncTask: onPostExecute : main
-
由上可以看出执行的顺序分别是:
- onPreExecute 在主线程执行准备工作
- doInBackground 在子线程执行耗时操作
- onProgressUpdate在UI主线程可以接受并显示子线程处理的结果
- onPostExecute 子线程处理完毕,在UI线程更新
简单使用大家都会,那么我们一起深入了解一下源码吧。
二、源码剖析
不同的Android源码可能会有出入,这个基于Android API 20
1.首先从AsyncTask初始化开始
public abstract class AsyncTask<Params, Progress, Result> {
注意到,在AsyncTask抽象类上面扒拉一大堆注释,也是教我们怎么使用,简单看重点:AsyncTask主要用于轻松使用UI Thread,用于辅助Thread和Handle使用,最好用在子线程短时间操作(大概几秒左右),长时间建议使用线程池。
-
再看AsyncTask的后缀泛型,给出了三个参数<Params, Progress, Result>分别是(后文还会提到):
- Params:发送给任务的参数类型
- Progress: 在此期间发布的进度类型
- Result: 后台结果的类型
-
在看类的初始化
1 ---------> 创建一个mHandler,并new了一个mWorker,存储参数 * call方法设置进程等级并调用doInBackground(mParams);---后面继续说道 public AsyncTask(@Nullable Looper callbackLooper) { mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper() ? getMainHandler() : new Handler(callbackLooper); mWorker = new WorkerRunnable<Params, Result>() { public Result call() throws Exception { mTaskInvoked.set(true); Result result = null; try { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //noinspection unchecked result = doInBackground(mParams); Binder.flushPendingCommands(); } catch (Throwable tr) { mCancelled.set(true); throw tr; } finally { postResult(result); } return result; } }; 2 --------->mWorker实现了Callable private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> { Params[] mParams; }
2. mWorker中实现call方法,并调用doInBackground
call里面首先设置了进程等级setThreadPriority-Process.THREAD_PRIORITY_BACKGROUND-10
调用doInBackground,并且操作worker中保存的params
Binder.flushPendingCommands() : 刷新命令道binder driver,用于长时间的进程持有资源释放处理
-
在finally中调用了postResult(result),result是初始化时泛型声明的返回结果类型
1 ---------> private Result postResult(Result result) { @SuppressWarnings("unchecked") Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(this, result)); message.sendToTarget(); return result; } 2 --------->静态内部类封装的消息传递,包含当前Task和Data(自定义类型) private static class AsyncTaskResult<Data> { final AsyncTask mTask; final Data[] mData; AsyncTaskResult(AsyncTask task, Data... data) { mTask = task; mData = data; } } 3 --------->getHandler返回上面初始化时创建的 private Handler getHandler() { return mHandler; }
3.看Handler构成的消息传递机制
-
getMainHandler,主线程的Looper
private static Handler getMainHandler() { synchronized (AsyncTask.class) { if (sHandler == null) { sHandler = new InternalHandler(Looper.getMainLooper()); } return sHandler; } }
-
InternalHandler与publishProgress:
1 --------->处理result和progress消息机制 private static class InternalHandler extends Handler { public InternalHandler(Looper looper) { super(looper); } @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"}) @Override public void handleMessage(Message msg) { AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj; switch (msg.what) { case MESSAGE_POST_RESULT: // There is only one result result.mTask.finish(result.mData[0]); break; case MESSAGE_POST_PROGRESS: result.mTask.onProgressUpdate(result.mData); break; } } } 2 --------->finish:结束,并标记状态:FINISHED * 如果是异常或者主动打断调用onCancelled * 否则调用 onPostExecute 结束,并传递result private void finish(Result result) { if (isCancelled()) { onCancelled(result); } else { onPostExecute(result); } mStatus = Status.FINISHED; } 3 --------->再看publishProgress,一样通过Handler机制传递,自定义的progress类型值 protected final void publishProgress(Progress... values) { if (!isCancelled()) { getHandler().obtainMessage(MESSAGE_POST_PROGRESS, new AsyncTaskResult<Progress>(this, values)).sendToTarget(); } }
4.接着看execute方法
首先是注释,从Android API 11开始,改为单线程执行,如果想要并行,使用executeOnExecutor传入线程池管理
-
看代码:
1 --------->返回本身,params传参为任务参数(我们先不管,接着看) @MainThread public final AsyncTask<Params, Progress, Result> execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); } 2 --------->executeOnExecutor传入 sDefaultExecutor * 这里有2个标记:RUNNING,FINISHED,印证上面说的,单线程执行,在执行完成前调用报错 * 在创建线程池前调用onPreExecute(); * 给mWorker赋值传入参数类型params public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec, Params... params) { 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; onPreExecute(); mWorker.mParams = params; exec.execute(mFuture); return this; } 3 ---------> 上述看出,它调了sDefaultExecutor.execute,并执行了FutureTask
5.接着看线程池sDefaultExecutor和execute方法
-
sDefaultExecutor成员变量中声明
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR; public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
看SerialExecutor,是AsyncTask中的私有静态内部类:
1 ---------> execute执行时,在mTasks双向队列中,末尾添加一个Runnable
* 并在同步情况下,通过线程池 THREAD_POOL_EXECUTOR执行该任务
private static class SerialExecutor implements Executor {
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive;
public synchronized void execute(final Runnable r) {
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
- 看线程池THREAD_POOL_EXECUTOR:
1 ---------> 创建了一个线程池,参数如下:
* 核心线程池大小2-4
* 最大线程池的大小根据CPU的内核计算CPU_COUNT * 2 + 1,
* KEEP_ALIVE_SECONDS
* 线程池队列sPoolWorkQueue,最大128
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128);
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
// We want at least 2 threads and at most 4 threads in the core pool,
// preferring to have 1 less than the CPU count to avoid saturating
// the CPU with background work
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final int KEEP_ALIVE_SECONDS = 30;
public static final Executor 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;
}
三、总结
AsyncTask的源码到上面就分析结束了,看起来非常的简单,但是设计全是非常的全面和方便。如果想要加深理解,需要详细的了解Android异步机制,Handler,以及Java线程池的学习。可以参考我后续发的一系列源码分析,一起来探索学习。