Android 源码解析之AsyncTask
AsyncTask相信大家都不陌生,它是為了簡(jiǎn)化異步請(qǐng)求、更新UI操作而誕生的。使用它不僅可以完成我們的網(wǎng)絡(luò)耗時(shí)操作,而且還可以在完成耗時(shí)操作后直接的更新我們所需要的UI組件。這使得它在android開發(fā)中成為炙手可熱的網(wǎng)絡(luò)請(qǐng)求工具類。
而今天我們就以源碼分析的形式來徹底的學(xué)習(xí)下它的實(shí)現(xiàn)過程。
首先,我們先看看AsyncTask的定義形式:
public abstract class AsyncTask<Params, Progress, Result> { }首先AsyncTask它是一個(gè)抽象類,包括三種泛型類型,具體含義如下:
- Params:它表示請(qǐng)求參數(shù)的類型
- Progress:執(zhí)行任務(wù)的進(jìn)度類型
- Result:返回結(jié)果的類型
但是以上三個(gè)參數(shù)并不是一定必須,在不需要時(shí)可以設(shè)置為Void,沒有返回類型。
然后我們看看它的執(zhí)行過程,包括以下幾個(gè)方法:
execute(Params... params),我們?cè)趫?zhí)行異步操作時(shí)會(huì)調(diào)用該方法,表示開始執(zhí)行任務(wù)。
protected void onPreExecute() {},在調(diào)用execute方法后,該方法就會(huì)得到執(zhí)行,它執(zhí)行在UI線程中,用來初始化一些UI空間等
protected abstract Result doInBackground(Params... params);在onPreExecute執(zhí)行完后將會(huì)執(zhí)行該方法,它執(zhí)行在后臺(tái),并接受一個(gè)Params類型的數(shù)組參數(shù),用于請(qǐng)求網(wǎng)絡(luò),并且它返回一個(gè)Result 類型的結(jié)果。該方法中可以在執(zhí)行網(wǎng)絡(luò)請(qǐng)求的同時(shí)更新請(qǐng)求進(jìn)度,調(diào)用publishProgress(Progress... values) 。
protected void onProgressUpdate(Progress... values) ,假如在doInBackground方法中調(diào)用了publishProgress方法,那么該方法就會(huì)得到執(zhí)行,它是執(zhí)行在UI線程的,根據(jù)values的值不停的更改進(jìn)度,以達(dá)到想要的效果。
protected void onPostExecute(Result result),該方法是在doInBackground方法執(zhí)行完畢后得到執(zhí)行,可根據(jù)doInBackground返回的結(jié)果進(jìn)行后續(xù)的UI操作,由此可見它是工作在UI線程中的。
經(jīng)過上面一系列的方法運(yùn)轉(zhuǎn),一個(gè)完整的AysncTask請(qǐng)求就正式的完成了任務(wù)。不僅完成了耗時(shí)操作還更新的UI組件,這就是它的魅力所在。但是這時(shí)候你該有疑問了,上面的方法都是你說執(zhí)行哪個(gè)就執(zhí)行哪個(gè),哪到底是怎么執(zhí)行的呢?
那么接下來就正式的揭開它的廬山正面目。
在正式介紹它的源碼之前,你必須知道new 一個(gè)類它所執(zhí)行的過程:
在new的過程中,它會(huì)首先一層一層的加載它所繼承的父類的成員變量及構(gòu)造方法
然后在加載自己的成員變量和構(gòu)造方法。
順序是不可變得。
那么看看在我們執(zhí)行 new AsyncTask()中,它到底加載了哪些成員呢?
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();private static final int CORE_POOL_SIZE = CPU_COUNT + 1;private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;private static final int KEEP_ALIVE = 1;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());}};private static final BlockingQueue<Runnable> sPoolWorkQueue =new LinkedBlockingQueue<Runnable>(128);public static final Executor THREAD_POOL_EXECUTOR= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);public static final Executor SERIAL_EXECUTOR = new SerialExecutor();private static final int MESSAGE_POST_RESULT = 0x1;private static final int MESSAGE_POST_PROGRESS = 0x2;private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;private static InternalHandler sHandler;private final WorkerRunnable<Params, Result> mWorker;private final FutureTask<Result> mFuture;private volatile Status mStatus = Status.PENDING;private final AtomicBoolean mCancelled = new AtomicBoolean();private final AtomicBoolean mTaskInvoked = new AtomicBoolean();private static class SerialExecutor implements Executor{...}public enum Status {PENDING,RUNNING,FINISHED,}看到這么一大堆是不是很麻頭皮,其實(shí)仔細(xì)拆分下來,你主要看幾個(gè)變量即可。
THREAD_POOL_EXECUTOR :這個(gè)成員變量從它THREAD_POOL_EXECUTOR = new ThreadPoolExecutor中可以看出,它是一個(gè)線程池,而ThreadPoolExecutor線程池中需要幾個(gè)參數(shù),如corePoolSize(核心線程數(shù))、maximumPoolSize(最大線程數(shù))、workQueue(任務(wù)隊(duì)列)、threadFactory(線程工程)等等,所以像CORE_POOL_SIZE,sPoolWorkQueue ,sThreadFactory 等成員變量,只是為了配置這個(gè)線程池而已。
sDefaultExecutor 這個(gè)成員變量是默認(rèn)的線程調(diào)度任務(wù),從上面可看出SERIAL_EXECUTOR則是一個(gè)序列化的任務(wù)調(diào)度,從sDefaultExecutor = SERIAL_EXECUTOR;中可以明確的知道sDefaultExecutor任務(wù)調(diào)度中是按先后順序執(zhí)行的。
sHandler顧名思義是一個(gè)handler,mWorker是一個(gè)工作線程,mFuture則是一個(gè)FutureTask,FutureTask是專門用于管理Runnable線程的,mStatus 則是一個(gè)枚舉,里面有三種狀態(tài),分別是未執(zhí)行,執(zhí)行中,以及執(zhí)行完成狀態(tài),默認(rèn)狀態(tài)是未執(zhí)行狀態(tài)。
所以我們只要理解好上面幾個(gè)變量可以不用害怕它一堆的初始化成員。
然后我們?cè)诳纯碅ysncTask的構(gòu)造方法中具體做了那些事:
public AsyncTask() {mWorker = new WorkerRunnable<Params, Result>() {public Result call() throws Exception {mTaskInvoked.set(true);Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);//noinspection uncheckedResult result = doInBackground(mParams);Binder.flushPendingCommands();return postResult(result);}};mFuture = new FutureTask<Result>(mWorker) {@Overrideprotected 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);}}};}簡(jiǎn)單來說,AsyncTask的成員變量中就只是初始化了兩個(gè)變量,mWorker 和 mFuture 。這兩個(gè)變量是非常重要的,后續(xù)的所有執(zhí)行過程都是由這兩個(gè)變量構(gòu)成或引導(dǎo)的。
首先mWorker 是一個(gè)抽象內(nèi)部類實(shí)例,是一個(gè)任務(wù)線程,它實(shí)現(xiàn)Callable接口中的call()方法
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {Params[] mParams;}然后mFuture 則是一個(gè)針對(duì)任務(wù)線程的管理類。專門用于管理任務(wù)線程的,可以使我們的任務(wù)得到更好的控制,來看看它的構(gòu)造方法吧:
public FutureTask(Callable<V> callable) {if (callable == null)throw new NullPointerException();this.callable = callable;this.state = NEW; // ensure visibility of callable}就是接受了我們的mWorker 對(duì)象以及把自身的狀態(tài)設(shè)置為NEW。
以上就是在new一個(gè)AsyncTask所進(jìn)行的所有操作,無非就是初始化了一些數(shù)據(jù)和變量。
下面來看看AysncTask的正式執(zhí)行。
我們所知道開啟一個(gè)AsyncTask任務(wù)所調(diào)用的方法是execute方法,該方法必須在主線程中調(diào)用。
public final AsyncTask<Params, Progress, Result> execute(Params... params) {return executeOnExecutor(sDefaultExecutor, params);}在調(diào)用execute方法后,該方法什么也沒做,只是把已初始化好的默認(rèn)序列任務(wù)線程sDefaultExecutor和傳遞進(jìn)來的數(shù)據(jù)params傳遞給了executeOnExecutor(),那么我們?cè)诳纯催@個(gè)方法做了哪些事情:
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;}executeOnExecutor()方法中首先判斷了AsyncTask的執(zhí)行狀態(tài),如果是正在執(zhí)行或是已經(jīng)結(jié)束執(zhí)行了,它就會(huì)報(bào)出一個(gè)IllegalStateException的異常,告訴你線程或是在執(zhí)行中或是已經(jīng)執(zhí)行完畢了。
只有在未執(zhí)行的狀態(tài)下,才可以進(jìn)行AsyncTask請(qǐng)求任務(wù),接下來它直接把AsyncTask的執(zhí)行狀態(tài)更改為Status.RUNNING,告訴其他任務(wù)該AsyncTask正在執(zhí)行中,保持執(zhí)行結(jié)果的一致性。然后就執(zhí)行了onPreExecute();由于execute方法是必須在主線程中執(zhí)行的,所以到目前為止還是在主線程中運(yùn)行,也就證明了onPreExecute()方法是在主線程中運(yùn)行的。
onPreExecute源碼中并沒有做什么事情,這對(duì)于我們來說,只需要重寫該方法就可以在主線程中進(jìn)行一些UI組件的初始化等操作。
- 接下來則是將我們所傳遞的數(shù)據(jù)賦值給mWorker的mParams變量,然后調(diào)用exec.execute(mFuture)方法,我們通過execute方法中知道exec其實(shí)就是一個(gè)sDefaultExecutor,sDefaultExecutor實(shí)則是一個(gè)SerialExecutor 序列線程,而mFuture我們?cè)跇?gòu)造方法中也很清楚的知道,它是一個(gè)封裝了mWorker線程的一個(gè)可管理的任務(wù)線程,那么在調(diào)用sDefaultExecutor的execute方法并傳遞進(jìn)了mFuture任務(wù)線程,那到底做了什么事情呢,我們來看下它的源碼:
源碼我們很清晰的知道在execute方法中最終的目的就是把mFuture任務(wù)線程賦值給一個(gè)Runnable 線程并放到了THREAD_POOL_EXECUTOR線程池中,由THREAD_POOL_EXECUTOR線程池來執(zhí)行mFuture線程任務(wù)。
那么接著我們看看在THREAD_POOL_EXECUTOR線程池中execute的方法中主要做了什么事情:
public void execute(Runnable command) {if (command == null)throw new NullPointerException();int c = ctl.get();if (workerCountOf(c) < corePoolSize) {if (addWorker(command, true))return;c = ctl.get();}if (isRunning(c) && workQueue.offer(command)) {int recheck = ctl.get();if (! isRunning(recheck) && remove(command))reject(command);else if (workerCountOf(recheck) == 0)addWorker(null, false);}else if (!addWorker(command, false))reject(command);}THREAD_POOL_EXECUTOR線程池中主要是判斷了傳遞的線程是否為空,是否小于當(dāng)前線程池中保存的核心線程數(shù),如果小于則直接執(zhí)行addWorker(command, true)方法,下面看看addWorker方法中的實(shí)現(xiàn)內(nèi)容:
private boolean addWorker(Runnable firstTask, boolean core) {...(前面代碼省略)boolean workerStarted = false;boolean workerAdded = false;Worker w = null;try {w = new Worker(firstTask);final Thread t = w.thread;if (t != null) {final ReentrantLock mainLock = this.mainLock;mainLock.lock();try {int rs = runStateOf(ctl.get());if (rs < SHUTDOWN ||(rs == SHUTDOWN && firstTask == null)) {if (t.isAlive()) throw new IllegalThreadStateException();workers.add(w);int s = workers.size();if (s > largestPoolSize)largestPoolSize = s;workerAdded = true;}} finally {mainLock.unlock();}if (workerAdded) {t.start();workerStarted = true;}}} finally {if (! workerStarted)addWorkerFailed(w);}return workerStarted;}我們只看主要的邏輯,首先是將我們的mFuture任務(wù)線程存放到了一個(gè)Worker的對(duì)象中,然后又從Worker對(duì)象中獲取到mFuture線程并賦值給了Thread ,接著把Worker對(duì)象放到workers的HashSet數(shù)據(jù)集合對(duì)象中,經(jīng)過獲取HashSet的大小并進(jìn)行一些判斷,把workerAdded 設(shè)置為true,最后開啟t.start();線程,由此進(jìn)入了子線程中。
那么接下來在開啟的子線程中又做了什么事情呢?
我們從上面的分析指導(dǎo)t.start()開啟就是一個(gè)mFuture的異步任務(wù)線程,那么它在哪執(zhí)行呢?
細(xì)心的朋友可以發(fā)現(xiàn),原來是在SerialExecutor 中的execute方法中我們的mFuture的run()早已在等待了線程的啟動(dòng),那么,我現(xiàn)在去看看mFuture的run()方法中做了什么工作吧
public void run() {if (state != NEW ||!U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))return;try {Callable<V> c = callable;if (c != null && state == NEW) {V result;boolean ran;try {result = c.call();ran = true;} catch (Throwable ex) {result = null;ran = false;setException(ex);}if (ran)set(result);}} finally {runner = null;int s = state;if (s >= INTERRUPTING)handlePossibleCancellationInterrupt(s);}}這段代碼很簡(jiǎn)單,一眼就可以看得出來就是利用我們?cè)跒閙Future初始化時(shí)傳遞的mWorker 對(duì)象實(shí)例并調(diào)用它的call()方法,我們先不管call怎么實(shí)現(xiàn)的,先來看看這個(gè)方法中的后續(xù)是什么。
接著它得到一個(gè)執(zhí)行結(jié)果,并把一個(gè)boolean類型的ran設(shè)置為true,最后根據(jù)ran調(diào)用set(result);方法,并把結(jié)果傳遞進(jìn)去,下面看看set的源碼:
protected void set(V v) {if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {outcome = v;U.putOrderedInt(this, STATE, NORMAL); // final statefinishCompletion();}}它主要調(diào)用了finishCompletion();在來看看finishCompletion的源碼:
private void finishCompletion() {// assert state > COMPLETING;for (WaitNode q; (q = waiters) != null;) {if (U.compareAndSwapObject(this, WAITERS, q, null)) {for (;;) {Thread t = q.thread;if (t != null) {q.thread = null;LockSupport.unpark(t);}WaitNode next = q.next;if (next == null)break;q.next = null; // unlink to help gcq = next;}break;}}done();callable = null; // to reduce footprint}在執(zhí)行完call中,把一些對(duì)象進(jìn)行還原,還調(diào)用了 done(),該方法就是在AsyncTask構(gòu)造方法中我們有看到它的實(shí)現(xiàn):
mFuture = new FutureTask<Result>(mWorker) {@Overrideprotected 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);}}};我們也說過FutureTask主要是用來管理異步線程任務(wù)的,那么在done方法中就有很好的體現(xiàn),在該方法中,它會(huì)判斷執(zhí)行的結(jié)果是否成功,成功后有沒有被發(fā)送,如果有發(fā)送它就不再發(fā)送消息,如果結(jié)果執(zhí)行成功,但沒有被發(fā)送它就會(huì)發(fā)送最終的執(zhí)行結(jié)果:
private void postResultIfNotInvoked(Result result) {final boolean wasTaskInvoked = mTaskInvoked.get();if (!wasTaskInvoked) {postResult(result);}}postResult方法的內(nèi)容我們推后一點(diǎn)講,那么現(xiàn)在我們來看看mWorker 中call()是怎么實(shí)現(xiàn)的:
mWorker = new WorkerRunnable<Params, Result>() {public Result call() throws Exception {mTaskInvoked.set(true);Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);//noinspection uncheckedResult result = doInBackground(mParams);Binder.flushPendingCommands();return postResult(result);}};在這里我們終于見到了我們所熟悉的一個(gè)方法doInBackground(),由此也可以知道其確實(shí)是在子線程運(yùn)行的,而doInBackground()方法在AsyncTask類中是一個(gè)抽象方法:
protected abstract Result doInBackground(Params... params);那么我們?cè)谥貙慸oInBackground()時(shí)就可以直接的在其中進(jìn)行一些耗時(shí)的網(wǎng)絡(luò)和IO操作了。
這里插上一句,假如在doInBackground()調(diào)用了publishProgress方法來更新進(jìn)度的話,那來看看它是怎么做的:
protected final void publishProgress(Progress... values) {if (!isCancelled()) {getHandler().obtainMessage(MESSAGE_POST_PROGRESS,new AsyncTaskResult<Progress>(this, values)).sendToTarget();}}publishProgress方法中主要是通過Hangler發(fā)送一條更新進(jìn)度的標(biāo)志用來更新進(jìn)度。這里的Hangler接受消息在下面和執(zhí)行結(jié)果一起講。
最后doInBackground()執(zhí)行獲取的Result 結(jié)果也將會(huì)傳遞到postResult(result);方法中,那么現(xiàn)在我們來看看它的源碼實(shí)現(xiàn):
private Result postResult(Result result) {@SuppressWarnings("unchecked")Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,new AsyncTaskResult<Result>(this, result));message.sendToTarget();return result;}private static Handler getHandler() {synchronized (AsyncTask.class) {if (sHandler == null) {sHandler = new InternalHandler();}return sHandler;}}private static class AsyncTaskResult<Data> {final AsyncTask mTask;final Data[] mData;AsyncTaskResult(AsyncTask task, Data... data) {mTask = task;mData = data;}}postResult中首先封裝了doInBackground異步執(zhí)行結(jié)果的AsyncTaskResult對(duì)象,然后獲取到一個(gè)Handler ,通過消息處理機(jī)制發(fā)送一條信息來切換到主線程中進(jìn)行UI界面的更換,消息處理機(jī)制不屬于本次博文的內(nèi)容所以不再細(xì)說,那來看看這個(gè)Handler是怎么處理這個(gè)消息內(nèi)容的。
private static class InternalHandler extends Handler {public InternalHandler() {super(Looper.getMainLooper());}@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})@Overridepublic void handleMessage(Message msg) {AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;switch (msg.what) {case MESSAGE_POST_RESULT:result.mTask.finish(result.mData[0]);break;case MESSAGE_POST_PROGRESS:result.mTask.onProgressUpdate(result.mData);break;}}}Handler中主要是根據(jù)消息標(biāo)志進(jìn)行區(qū)分是更新進(jìn)度還是執(zhí)行結(jié)果:
如果是更新進(jìn)度則調(diào)用AsyncTask的onProgressUpdate方法來更新內(nèi)容,由于通過Handler已轉(zhuǎn)變?yōu)橹骶€程中,所以我們?cè)谥貙懺摲椒〞r(shí)可以直接更新UI組件。
如果是執(zhí)行結(jié)果則AsyncTask的finish(result.mData[0]);并把結(jié)果數(shù)據(jù)傳遞過去,來看看finish()中是怎么實(shí)現(xiàn)的:
private void finish(Result result) {if (isCancelled()) {onCancelled(result);} else {onPostExecute(result);}mStatus = Status.FINISHED;}finish()方法中也非常的簡(jiǎn)單,首先判斷是否為取消線程,否則的話則執(zhí)行onPostExecute(result)方法,由此我們?cè)谥貙懥薿nPostExecute方法后可以直接的更新我們的UI組件。
最后把AsyncTask的狀態(tài)改為完成狀態(tài),至此整個(gè)AsyncTask生命周期就執(zhí)行完畢了。
好了,至此AsyncTask整個(gè)執(zhí)行過程就完全講完了,相信大家也學(xué)到了不少東西,建議大家有空自己對(duì)著源碼在梳理一遍,畢竟自己總結(jié)出來的印象就更深刻。
今天就到這里吧,祝大家生活愉快。
更多資訊請(qǐng)關(guān)注微信平臺(tái),有博客更新會(huì)及時(shí)通知。愛學(xué)習(xí)愛技術(shù)。
轉(zhuǎn)載于:https://www.cnblogs.com/guanmanman/p/6076418.html
總結(jié)
以上是生活随笔為你收集整理的Android 源码解析之AsyncTask的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 利用 Chef 在 Red Hat En
- 下一篇: fiddler无法获取Android端h