内容简介: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 四步工作流程
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Pro Django
Marty Alchin / Apress / 2008-11-24 / USD 49.99
Django is the leading Python web application development framework. Learn how to leverage the Django web framework to its full potential in this advanced tutorial and reference. Endorsed by Django, Pr......一起来看看 《Pro Django》 这本书的介绍吧!