内容简介:Android多线程-AsyncTask工作流程(源码)
AsyncTask的源码是很简单的,看着并不复杂。只是对Handler和ThreadPoolExecutor进行了一下封装。
基于api25(7.1)的代码,
使用起来也是很简单的,看 上个就知道了 。一般要继承AsyncTask并重写下面几个方法,这些方法的执行顺序一目了然:
原文地址
//任务执行前调用 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 InternalHandlerextends 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 staticHandlergetHandler(){ 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 SerialExecutorimplements Executor{ final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>(); Runnable mActive; public synchronized void execute(finalRunnable 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); publicThreadnewThread(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>() { publicResultcall()throwsException{ 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 finalAsyncTask<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>() { publicResultcall()throwsException{ 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 InternalHandlerextends 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工作流程(源码)
- Golang 源码学习调度逻辑(三):工作线程的执行流程与调度循环
- gitFlow工作流程
- 初识 Git 工作流程
- [译] Git 工作流程
- Keras 四步工作流程
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Linux 系统编程(第二版)
Robert Love / 东南大学出版社 / 2014-1-1 / 78
如何编写那些直接依赖于Linux内核和核心系统库提供的服务的软件?通过《Linux系统编程(第2版)(影印版)》,Linux内核参与者RobertLove(洛夫)为你提供了Linux系统编程方面的教程,Linux系统调用的参考手册,以及对于如何编写更聪明和更快的代码的来自内部人士的建议。Love清晰地指出了POSIX标准函数和Linux特别提供服务之间的差异。通过关于多线程的新章节,这本修订和扩展......一起来看看 《Linux 系统编程(第二版)》 这本书的介绍吧!