摘要:的用法的聲明如下是一個(gè)抽象類,同時(shí)也是一個(gè)泛型類。多線程問題通過以上分析,涉及到兩個(gè)線程池。是串行線程池,使用隊(duì)列管理任務(wù)對象。是真正執(zhí)行任務(wù)的線程池,若要實(shí)現(xiàn)并行執(zhí)行任務(wù),則可自定義線程池,傳入方法作為線程池對象。
AsyncTask 分析
AsyncTask簡介位置:frameworksasecorejavaandroidosAsyncTask.java
在Android中,所有的UI更新操作必須要在主線程中進(jìn)行,而耗時(shí)操作(如訪問網(wǎng)絡(luò)、加載圖片、IO操作等)需要在子線程中進(jìn)行,線程間的交互需要借助Android的異步消息處理機(jī)制,也就是Handler。但是為了更方便地讓子線程與主線程交互,更新UI元素,Android系統(tǒng)提供了輕量級的異步任務(wù)類AsyncTask。
AsyncTask的用法AsyncTask的聲明如下:
public abstract class AsyncTask
AsyncTask是一個(gè)抽象類,同時(shí)也是一個(gè)泛型類。在使用時(shí)需要?jiǎng)?chuàng)建子類去繼承它,并指定相應(yīng)的泛型類型參數(shù)。三個(gè)參數(shù)的含義
Params
執(zhí)行AsyncTask時(shí)需要傳入的參數(shù),用于執(zhí)行后臺(tái)任務(wù)。
Progress
顯示任務(wù)進(jìn)度單位。
Result
任務(wù)執(zhí)行完畢后返回的結(jié)果
一個(gè)簡單的AsyncTask使用示例:
class DownloadTask extends AsyncTask{ @Override protected void onPreExecute() { progressDialog.show(); } @Override protected Boolean doInBackground(Void... params) { try { while (true) { int downloadPercent = doDownload(); publishProgress(downloadPercent); if (downloadPercent >= 100) { break; } } } catch (Exception e) { return false; } return true; } @Override protected void onProgressUpdate(Integer... values) { progressDialog.setMessage("當(dāng)前下載進(jìn)度:" + values[0] + "%"); } @Override protected void onPostExecute(Boolean result) { progressDialog.dismiss(); if (result) { Toast.makeText(context, "下載成功", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(context, "下載失敗", Toast.LENGTH_SHORT).show(); } } }
onPreExecute
此方法會(huì)在后臺(tái)任務(wù)執(zhí)行前被調(diào)用,用于進(jìn)行一些準(zhǔn)備工作,在主線程執(zhí)行。
doInBackground
此方法為要執(zhí)行的后臺(tái)任務(wù),在子線程中執(zhí)行。不能進(jìn)行UI操作。
onProgressUpdate
顯示任務(wù)執(zhí)行進(jìn)度,在doInBackground中調(diào)用publishProgress(Progress... values),values會(huì)傳入此方法中,進(jìn)行進(jìn)度顯示。在主線程執(zhí)行。
onPostExecute
當(dāng)后臺(tái)任務(wù)執(zhí)行完畢后,通過return語句返回執(zhí)行結(jié)果,執(zhí)行結(jié)果傳入此方法作為參數(shù)
任務(wù)的啟動(dòng):
new DownloadTask().execute();AsyncTask源碼分析
基于Android 6.0源碼
首先看AsyncTask的構(gòu)造函數(shù):
public AsyncTask() { mWorker = new WorkerRunnable() { public Result call() throws Exception { mTaskInvoked.set(true); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //noinspection unchecked Result result = doInBackground(mParams); Binder.flushPendingCommands(); return postResult(result); } }; mFuture = new FutureTask (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); } } }; }
構(gòu)造函數(shù)里初始化了兩個(gè)對象:mWorker和mFuture,mWorker是WorkerRunnable抽象類,實(shí)現(xiàn)了Callable接口。在mWorker的call()方法中,mTaskInvoked.set(true)表示當(dāng)前任務(wù)已被調(diào)用過,然后設(shè)置當(dāng)前線程的優(yōu)先級。接著調(diào)用AsyncTask的doInBackground(mParams)方法執(zhí)行后臺(tái)任務(wù),并將執(zhí)行結(jié)果存入result傳入postResult方法。因此,要執(zhí)行的后臺(tái)任務(wù)包含在了AsyncTask的mWorker的call()方法中。
然后是mFuture,mFuture是一個(gè)FutureTask類對象,在構(gòu)造方法中傳入mWorker作為參數(shù)。mFuture其實(shí)是一個(gè)封裝了mWorker的FutureTask對象,F(xiàn)utureTask類實(shí)現(xiàn)了FutureRunnable接口,通過這個(gè)接口可以方便的取消后臺(tái)任務(wù)以及獲取后臺(tái)任務(wù)的執(zhí)行結(jié)果,具體可參考:Java并發(fā)編程:Callable、Future和FutureTask。
由上分析可知:后臺(tái)任務(wù)在mWorker的call()方法中,當(dāng)call()被執(zhí)行時(shí)后臺(tái)任務(wù)doInBackground也就會(huì)被執(zhí)行了。那么何時(shí)才會(huì)被執(zhí)行?因?yàn)閙Worker又封裝在了mFuture中,因此當(dāng)mFuture對象被提交到AsyncTask包含的線程池執(zhí)行時(shí),call方法就會(huì)被調(diào)用,自定義的后臺(tái)任務(wù)也就開始執(zhí)行了。
要啟動(dòng)某一個(gè)任務(wù),就需要調(diào)用該任務(wù)的execute()方法,下面看execute()方法的源碼:
public final AsyncTaskexecute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); }
在執(zhí)行execute時(shí)傳入params參數(shù),這個(gè)參數(shù)會(huì)一層一層傳遞到doInBackground方法中,方法中調(diào)用了executeOnExecutor并將其返回值返回,傳入了兩個(gè)參數(shù),其中sDefaultExecutor是AsyncTask默認(rèn)的線程池。
下面看executeOnExecutor方法:
public final AsyncTaskexecuteOnExecutor(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方法中,首先判斷任務(wù)的狀態(tài),當(dāng)任務(wù)正在運(yùn)行或已經(jīng)結(jié)束時(shí)會(huì)拋出異常。
然后調(diào)用了AsyncTask的 onPreExecute() 方法,因此前面自定義的AsyncTask類中,onPreExecute()方法會(huì)第一個(gè)被執(zhí)行。
然后將傳入的params賦值給mWorker的mParams變量
然后執(zhí)行exec的execute()方法,傳入mFuture作為參數(shù),exec就是前面?zhèn)鬟M(jìn)來的sDefaultExecutor
接下來看看sDefaultExecutor
public static final Executor SERIAL_EXECUTOR = new SerialExecutor(); …… private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
sDefaultExecutor是一個(gè)靜態(tài)的SerialExecutor常量,SerialExecutor類定義如下:
private static class SerialExecutor implements Executor { final ArrayDequemTasks = new ArrayDeque (); 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); } } }
SerialExecutor類是一個(gè)串行線程池,其中定義了一個(gè)mTasks任務(wù)緩存隊(duì)列。
在execute方法中,mTasks.offer向緩存隊(duì)列添加了一個(gè)Runnable任務(wù),任務(wù)中run方法執(zhí)行了r.run(),其實(shí)就是調(diào)用前面?zhèn)魅氲膍Future對象的run方法,而mFuture的run方法內(nèi)部會(huì)調(diào)用mWorker的call方法,然后就會(huì)調(diào)用doInBackground方法,因此后臺(tái)任務(wù)就開始執(zhí)行了。
提交到任務(wù)緩存隊(duì)列中的任務(wù)什么時(shí)候會(huì)被執(zhí)行呢?
SerialExecutor中定義了一個(gè)Runnable對象mActive,表示當(dāng)前正在執(zhí)行的任務(wù),當(dāng)?shù)谝淮螆?zhí)行execute時(shí),mActive肯定是null,因此進(jìn)入if語句執(zhí)行scheduleNext(),取出第一個(gè)任務(wù)賦給mActive并判斷是否為null,然后調(diào)用THREAD_POOL_EXECUTOR.execute()方法傳入mActive參數(shù),執(zhí)行取出的mActive引用的任務(wù)對象。此時(shí)后臺(tái)任務(wù)真正開始。
當(dāng)有新的任務(wù)被執(zhí)行時(shí),同樣會(huì)offer()方法將傳入的Runnable添加到隊(duì)列的尾部,在后續(xù)操作判斷mActive就是非null,則不會(huì)進(jìn)入if語句中。
但是,第一個(gè)任務(wù)被執(zhí)行時(shí),在Runnable的run方法,中finally中調(diào)用了scheduleNext()方法,因此每當(dāng)一個(gè)任務(wù)執(zhí)行完畢后,下一個(gè)任務(wù)才會(huì)得到執(zhí)行,SerialExecutor模仿的是單一線程池的效果,如果啟動(dòng)了很多任務(wù),同一時(shí)刻只會(huì)有一個(gè)線程正在執(zhí)行,其余的均保存在任務(wù)隊(duì)列中,處于等待狀態(tài)。
由上可知,真正執(zhí)行任務(wù)的是THREAD_POOL_EXECUTOR
public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
THREAD_POOL_EXECUTOR是一個(gè)線程池,它的配置如下:
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 BlockingQueuesPoolWorkQueue = new LinkedBlockingQueue (128);
核心線程數(shù)corePoolSize為CPU數(shù)加一;
最大線程數(shù)maximumPoolSize為CPU數(shù)的二倍加一;
存活時(shí)間為1秒;
任務(wù)緩存隊(duì)列為LinkedBlockingQueue,最多緩存128個(gè)任務(wù)。
前面說了,當(dāng)子線程執(zhí)行任務(wù)時(shí),其實(shí)是執(zhí)行mFuture對象的run方法,也就是執(zhí)行mWorker對象的call()方法
下面再看一下mWorker對象的call()方法:
public Result call() throws Exception { mTaskInvoked.set(true); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //noinspection unchecked Result result = doInBackground(mParams); Binder.flushPendingCommands(); return postResult(result); }
doInBackground的執(zhí)行結(jié)果保存在result,作為參數(shù)傳入postResult()方法
postResult():
private Result postResult(Result result) { @SuppressWarnings("unchecked") Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult(this, result)); message.sendToTarget(); return result; }
這里通過AsyncTask類內(nèi)部的Handler對象發(fā)出一條MESSAGE_POST_RESULT消息,消息內(nèi)保存了AsyncTaskResult對象,該對象封裝了任務(wù)的執(zhí)行結(jié)果。
下面看一下這個(gè)Handler的相關(guān)源碼:
private static Handler getHandler() { synchronized (AsyncTask.class) { if (sHandler == null) { sHandler = new InternalHandler(); } return 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; } } }
在主線程創(chuàng)建一個(gè)sHandler對象
收到MESSAGE_POST_PROGRESS消息后,會(huì)調(diào)用onProgressUpdate方法,MESSAGE_POST_PROGRESS消息通過publishProgress方法發(fā)送,我們常會(huì)在doInBackground方法中調(diào)用這個(gè)方法,用于回傳任務(wù)執(zhí)行進(jìn)度。
protected final void publishProgress(Progress... values) { if (!isCancelled()) { getHandler().obtainMessage(MESSAGE_POST_PROGRESS, new AsyncTaskResult
當(dāng)sHandler收到MESSAGE_POST_RESULT消息后,會(huì)調(diào)用finish方法
private void finish(Result result) { if (isCancelled()) { onCancelled(result); } else { onPostExecute(result); } mStatus = Status.FINISHED; }
在finish方法中,首先判斷任務(wù)的狀態(tài),然后執(zhí)行onPostExecute方法,最后設(shè)置任務(wù)狀態(tài)為FINISHED,當(dāng)前的AsyncTask任務(wù)全部執(zhí)行完畢。
多線程問題通過以上分析,AsyncTask涉及到兩個(gè)線程池:SerialExecutor、ThreadPoolExecutor。
SerialExecutor是串行線程池,使用ArrayDeque隊(duì)列管理任務(wù)(Runnable對象)。它同時(shí)只能執(zhí)行一個(gè)任務(wù),多個(gè)任務(wù)要等待上一個(gè)任務(wù)執(zhí)行完畢才能繼續(xù)執(zhí)行下一個(gè)。它在AsyncTask中的作用是保證任務(wù)按順序地一個(gè)接一個(gè)串行執(zhí)行。
ThreadPoolExecutor是真正執(zhí)行任務(wù)的線程池,若要實(shí)現(xiàn)并行執(zhí)行任務(wù),則可自定義線程池,傳入executeOnExecutor(Executor exec, Params... params)方法作為線程池對象。如:
Executor exec = new ThreadPoolExecutor(15, 200, 10, TimeUnit.SECONDS, new LinkedBlockingQueue()); new DownloadTask().executeOnExecutor(exec,params);
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/67445.html
摘要:異步任務(wù)的構(gòu)造方法主要用于初始化線程池先關(guān)的成員變量創(chuàng)建一個(gè)新的異步任務(wù)。所以,我們是必須確保在銷毀活動(dòng)之前取消任務(wù)。 目錄介紹 01.先看下AsyncTask用法 02.AsyncTask源碼深入分析 2.1 構(gòu)造方法源碼分析 2.2 看execute(Params... params)方法 2.3 mWorker和mFuture的創(chuàng)建過程 03.異步機(jī)制的實(shí)現(xiàn) 04.不同...
閱讀 2643·2023-04-26 02:17
閱讀 1616·2021-11-24 09:39
閱讀 1078·2021-11-18 13:13
閱讀 2631·2021-09-02 15:11
閱讀 2774·2019-08-30 15:48
閱讀 3410·2019-08-30 14:00
閱讀 2438·2019-08-29 13:43
閱讀 662·2019-08-29 13:07