Android多线程-AsyncTask工作流程(源码)
2017-05-31 15:43
393 查看
AsyncTask的源码是很简单的,看着并不复杂。只是对Handler和ThreadPoolExecutor进行了一下封装。
基于api25(7.1)的代码,
使用起来也是很简单的,看上个就知道了。一般要继承AsyncTask并重写下面几个方法,这些方法的执行顺序一目了然:
原文地址 http://blog.csdn.net/qq_25806863/article/details/72820844
只有
然后通常的调用方法是这样的:
首先有一个变量sHandler。
InternalHandler是一个静态内部类
在这个构造方法中可以看出,InternalHandler使用了主线程也就是UI线程的Looper来处理消息,所以这个Handler收到的消息会在主线程中处理。使用这个Handler就达到了跟主线程进行交互的目的。
然后提供了一个方法getHandler,用单例来获取唯一的一个InternalHandler。
在这里可以看见连个线程池,
这两个线程池关系到了为什么AsyncTask的任务是串行的。在ActivityThread中有这样一段代码:
看来只有当版本小于13的时候,才会将
直接使用
核心线程数,其中
最大线程数,是CPU核心数的2倍+1.
空闲线程存活时间,30 。根据第四个参数
使用了
这个只是给每个线程池中创建的额线程起了个名字,叫
然后设置语序核心线程空闲超时
这是一个中规中矩的线程池,然而默认使用的线程池并不是这个。而是下面的
当调用他的
然后下面会判断
在这个方法中,会调用队列的
因为每个任务经过加工都加上了
由此可见,这个队列仅仅起到一个排序功能,是各个任务依次执行,真正的执行还是交给了线程池
当然就有一个表示状态的变量,
这个类就是个CallAble接口,里面增加了一个参数数组。
看着调用方法:
先实现一个AsyncTask,这时要定义三个参数类型,
先new一个,然后调用
new的时候肯定会调用构造方法
这个任务其实才是后台任务,所以这个任务就是真正的AsyncTask的任务了。
然后就调用了
这个方法是真正开始执行任务的方法,一般都会传入个参数Params。
里面直接调用了
这里先判断任务的状态
当
然后就调用到了
一直到这时候都还是在原来的线程中运行,并没有开启多线程。所以这个方法也是在原来的线程中运行的。
然后调用传入的线程池的
首先把
然后调用重写过的
出现异常时,将
最终都会调用
这个方法也很简单:
然后通过这个Handler发送消息,消息内容是
然后整个工作就完成了。
在
这个方法贤惠判断任务是否取消,如果取消了就什么都不做。
没取消就也用
这些方法最终都是以通过Handler发送个消息结束,所以后面的就是Handler的事了
之前已经看过了这个类:
在
当
如果重写过这个方法,就可以根据这个值更新进度。
调用里面的
里面也是先判断是否取消,取消了就调用取消的回调
整个任务结束。
基于api25(7.1)的代码,
使用起来也是很简单的,看上个就知道了。一般要继承AsyncTask并重写下面几个方法,这些方法的执行顺序一目了然:
原文地址 http://blog.csdn.net/qq_25806863/article/details/72820844
//任务执行前调用 protected void onPreExecute() {} //执行后台任务 protected abstract Result doInBackground(Params... params); //返回任务执行结果 protected void onPostExecute(Result result) {} //返回任务执行进度 protected void onProgressUpdate(Progress... values) {} //任务取消时调用 protected void onCancelled() {}
只有
doInBackground一个方法是抽象的,必须重写,其他的可以不用重写。
然后通常的调用方法是这样的:
new MyAsyncTask().execute();
Handler和线程池
既然是对Handler和线程池的封装,就先看看封装的什么用的Handler和线程池。都是定义在AsyncTask类中。handler
private static InternalHandler sHandler; private static class InternalHandler extends Handler { public InternalHandler() { super(Looper.getMainLooper()); } @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; } } } private static Handler getHandler() { synchronized (AsyncTask.class) { if (sHandler == null) { sHandler = new InternalHandler(); } return sHandler; } }
首先有一个变量sHandler。
InternalHandler是一个静态内部类
在这个构造方法中可以看出,InternalHandler使用了主线程也就是UI线程的Looper来处理消息,所以这个Handler收到的消息会在主线程中处理。使用这个Handler就达到了跟主线程进行交互的目的。
然后提供了一个方法getHandler,用单例来获取唯一的一个InternalHandler。
线程池
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; } public static final Executor SERIAL_EXECUTOR = new SerialExecutor(); //默认的线程池 private static volatile Executor sDefaultExecutor = SERIAL_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); } } } /** @hide */ public static void setDefaultExecutor(Executor exec) { sDefaultExecutor = exec; }
在这里可以看见连个线程池,
THREAD_POOL_EXECUTOR和
SERIAL_EXECUTOR,以及一个默认使用的线程池变量
sDefaultExecutor。
这两个线程池关系到了为什么AsyncTask的任务是串行的。在ActivityThread中有这样一段代码:
//android.os.Build.VERSION_CODES.HONEYCOMB_MR1=12 if (data.appInfo.targetSdkVersion <= android.os.Build.VERSION_CODES.HONEYCOMB_MR1) { AsyncTask.setDefaultExecutor(AsyncTask.THREAD_POOL_EXECUTOR); }
看来只有当版本小于13的时候,才会将
THREAD_POOL_EXECUTOR作为默认线程池,可以并行执行任务。
THREAD_POOL_EXECUTOR
其中THREAD_POOL_EXECUTOR是在静态代码块中定义的,在类加载的时候就执行了,而且只会执行一次。
直接使用
ThreadPoolExecutor的构造方法来构造了一个线程池,来看一下参数:
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
核心线程数,其中
CPU_COUNT = Runtime.getRuntime().availableProcessors()表示CPU数量。最低两个,最多四个。
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
最大线程数,是CPU核心数的2倍+1.
private static final int KEEP_ALIVE_SECONDS = 30;
空闲线程存活时间,30 。根据第四个参数
TimeUnit.SECONDS知道是30秒。
private static final BlockingQueue<Runnable> sPoolWorkQueue =new LinkedBlockingQueue<Runnable>(128);
使用了
LinkedBlockingQueue,超过核心线程数量的任务会在队列中排队。
private static final ThreadFactory sThreadFactory = new ThreadFactory() { private final AtomicInteger mCount = new AtomicInteger(1); public Thread newThread(Runnable r) { return new Thread(r, "AsyncTask #" + mCount.getAndIncrement()); } };
这个只是给每个线程池中创建的额线程起了个名字,叫
AsyncTask # 数字,数字自增长。
然后设置语序核心线程空闲超时
threadPoolExecutor.allowCoreThreadTimeOut(true)。
这是一个中规中矩的线程池,然而默认使用的线程池并不是这个。而是下面的
SERIAL_EXECUTOR
SERIAL_EXECUTOR
SERIAL_EXECUTOR中维护了一个双端数组队列
mTasks,里面存放的Runnable。
当调用他的
execute方法执行
Runnable时,他会把这个
Runnable的
run方法和
scheduleNext()方法重新加工包装成一个新的
Runnable放在队列中。
然后下面会判断
mActive是不是空的,第一次肯定是空的,所以会执行
scheduleNext()方法。
在这个方法中,会调用队列的
poll方法取出一个
Runnable,然后调用上面的线程池
THREAD_POOL_EXECUTOR来执行任务。
因为每个任务经过加工都加上了
scheduleNext()方法,所以队列中的任务都会按顺序执行完。
由此可见,这个队列仅仅起到一个排序功能,是各个任务依次执行,真正的执行还是交给了线程池
SERIAL_EXECUTOR.
AsyncTask的其他内部类
状态Status
AsyncTask有一个枚举类定义了三个状态:public enum Status { /** * Indicates that the task has not been executed yet. * 表明任务尚未执行 */ PENDING, /** * Indicates that the task is running. * 表明任务正在执行 */ RUNNING, /** * Indicates that {@link AsyncTask#onPostExecute} has finished. * 表明onPostExecute已经结束 */ FINISHED, }
当然就有一个表示状态的变量,
mStatus默认是
Status.PENDING:
private volatile Status mStatus = Status.PENDING;
WorkerRunnable
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> { Params[] mParams; }
这个类就是个CallAble接口,里面增加了一个参数数组。
AsyncTaskResult
这个类其实就是个存储类,保存了一个AsyncTask和
Data[].
private static class AsyncTaskResult<Data> { final AsyncTask mTask; final Data[] mData; AsyncTaskResult(AsyncTask task, Data... data) { mTask = task; mData = data; } }
运行过程
上面的都准备好了,下面就能运行了。看着调用方法:
new MyAsyncTask().execute();
先实现一个AsyncTask,这时要定义三个参数类型,
AsyncTask<Params, Progress, Result>
先new一个,然后调用
execute方法
new的时候肯定会调用构造方法
构造方法
AsyncTask的构造方法中初始化了两个变量:private final WorkerRunnable<Params, Result> mWorker; private final FutureTask<Result> mFuture; private final AtomicBoolean mTaskInvoked = new AtomicBoolean(); public AsyncTask() { 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; } }; 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); } } }; }
mWorker前面看到了,是一个
WorkerRunnable,所以要重写
call方法。
这个任务其实才是后台任务,所以这个任务就是真正的AsyncTask的任务了。
然后就调用了
doInBackground(mParams),把参数穿了进去。
mFuture是个
FutureTask,他把上面的
mWorker又进行了一次包装,会先执行
mWorker的
call方法中的内容,再执行
done()。
execute
public final AsyncTask<Params, Progress, Result>execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
这个方法是真正开始执行任务的方法,一般都会传入个参数Params。
里面直接调用了
executeOnExecutor(sDefaultExecutor, params)方法,使用的线程池是默认的 ,也就是上面的
SERIAL_EXECUTOR。串行执行任务。
onPreExecute
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;
}
这里先判断任务的状态
mStatus,如果是正在运行或者说运行结束了,都会抛异常。所以一个任务只能执行一次
executef方法,一个任务只能执行一次,不能重复执行。
当
mStatus是
PENDING的时候,先
mStatus = Status.RUNNING表示任务正在执行了。
然后就调用到了
onPreExecute()方法。
mWorker.mParams = params前面看见
WorkerRunnable中有一个变量
Params[] mParams,保存了传入的参数。
一直到这时候都还是在原来的线程中运行,并没有开启多线程。所以这个方法也是在原来的线程中运行的。
然后调用传入的线程池的
execute方法,来执行构造方法中新建的
mFuture。这个时候就使用线程池开新线程了。
doInBackground
mFuture里有个
mWorker,会执行他的call方法,这个方法中的内容都会在子线程中运行,其中包括了
doInBackground,他的参数
mParams是
WorkerRunnable里的变量。:
mWorker = new WorkerRunnable<Params, Result>() { public Result call() throws Exception { mTaskInvoked.set(true); Result result = null; try { ... result = doInBackground(mParams); ... } catch (Throwable tr) { mCancelled.set(true); throw tr; } finally { postResult(result); } return result; } };
首先把
mTaskInvoked设置为
true表示这个任务已经开始了。
然后调用重写过的
doInBackground方法,运行咱们需要后台运行的任务。
doInBackground有一个返回值,也是个泛型。
出现异常时,将
mCancelled设置为
true,表示任务取消了。
最终都会调用
postResult(result)方法。
这个方法也很简单:
private Result postResult(Result result) { Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(this, result)); message.sendToTarget(); return result; }
getHandler()前面知道是通过单例获取到一个使用主线程
Looper创建的
Handler,就是
InnerHandler,所以他对消息的处理会回到主线程中。
然后通过这个Handler发送消息,消息内容是
new AsyncTaskResult<Result>(this, result)。前面也看了这是个载体,将这个
AsyncTask本身和后台任务
doInBackground的返回结果传了进去。
然后整个工作就完成了。
onProgressUpdate
这个方法用来更新进度,不能直接调用,要通过publishProgress方法来调用。
在
doInBackground,通常会手动调用
publishProgress方法来更新进度
protected final void publishProgress(Progress... values) { if (!isCancelled()) { getHandler().obtainMessage(MESSAGE_POST_PROGRESS, new AsyncTaskResult<Progress>(this, values)).sendToTarget(); } }
这个方法贤惠判断任务是否取消,如果取消了就什么都不做。
没取消就也用
InnerHandler发送消息,内容是
new AsyncTaskResult<Progress>(this, values)。传入当前的
AsyncTask和进度信息
values.
这些方法最终都是以通过Handler发送个消息结束,所以后面的就是Handler的事了
之前已经看过了这个类:
private static class InternalHandler extends Handler { public InternalHandler() { super(Looper.getMainLooper()); } @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; } } }
在
handleMessage中能看到,
result是个
AsyncTaskResult类型,在前面也知道这个里面保存了
AsyncTask和要传递的数据。前面两个消息携带的信息也是这个类型。
当
msg.what==MESSAGE_POST_PROGRESS的时候,表示要更新进度,就先从
result中拿到里面的
AsyncTask->result.mTask,然后调用他的
onProgressUpdate方法,参数是
result中的
mData->result.mData。
如果重写过这个方法,就可以根据这个值更新进度。
onPostExecute
当msg.what==MESSAGE_POST_RESULT的时候,表示有结果了,这是后台任务已经执行结束了。
调用里面的
AsyncTask的
finish方法,参数是消息里的
mData。
private void finish(Result result) { if (isCancelled()) { onCancelled(result); } else { onPostExecute(result); } mStatus = Status.FINISHED; }
里面也是先判断是否取消,取消了就调用取消的回调
onCancelled,没取消就调用正常的回调
onPostExecute,并最后把任务状态改为
Status.FINISHED。
整个任务结束。
相关文章推荐
- Android基于源码分析AsyncTask的工作流程
- Android多线程(二)AsyncTask源码分析
- android之多线程工作(一)AsyncTask
- Android多线程(二)AsyncTask源码分析
- Android BroadcastReceiver的工作流程源码分析(8.0)
- Android多线程之AsyncTask源码分析
- android多线程之AsyncTask源码分析
- AsyncTask工作流程源码分析
- Android之多线程工作-AsyncTask与handler
- 从源码分析Android的Volley库的工作流程
- Android多线程(三)AsyncTask源码分析(Android7.0)
- Android之多线程工作-AsyncTask与handler
- Android 多线程:AsyncTask的原理 及其源码分析
- 【Android】结合源码解析Android消息队列工作流程
- Android之多线程工作-AsyncTask与handler
- android开发之源码级分析(系统启动流程 & Handler消息机制 & AsyncTask机制)
- Android之多线程工作-AsyncTask与handler
- Android之多线程工作-AsyncTask与handler
- Android进阶——多线程系列之异步任务AsyncTask的使用与源码分析
- Android MMS 源码流程