摘要:在這里又調(diào)用我們發(fā)現(xiàn)在線程先調(diào)用了,將傳入的參數(shù)賦值給,然后調(diào)用了參數(shù)的方法,并且將作為參數(shù)傳入,這里就設(shè)計到了三個對象在中傳入,來看看它們的賦值在哪里我們發(fā)現(xiàn)的賦值默認(rèn)就是,也就是一個順序執(zhí)行的線程池,內(nèi)部實現(xiàn)有一個任務(wù)隊列。
在之前的文章深入探究了Handler,我們知道Android的消息機(jī)制主要靠Handler來實現(xiàn),但是在Handler的使用中,忽略內(nèi)存泄露的問題,不管是代碼量還是理解程度上都顯得有點不盡人意,所以Google官方幫我們在Handler的基礎(chǔ)上封裝出了AsyncTask。但是在使用AsyncTask的時候有很多細(xì)節(jié)需要注意,它的優(yōu)點到底體現(xiàn)在哪里?還是來看看源碼一探究竟。
怎么使用來一段平常簡單使用AsyncTask來異步操作UI線程的情況,首先新建一個類繼承AsyncTask,構(gòu)造函數(shù)傳入我們要操作的組件(ProgressBar和TextView)
class MAsyncTask extends AsyncTask{ private ProgressBar mProgressBar; private TextView mTextView; public MAsyncTask(ProgressBar mProgressBar, TextView mTextView) { this.mProgressBar = mProgressBar; this.mTextView = mTextView; } @Override protected void onPreExecute() { mTextView.setText("開始執(zhí)行"); super.onPreExecute(); } @Override protected String doInBackground(Void... params) { for(int i = 0; i <= 100; i++){ publishProgress(i);//此行代碼對應(yīng)下面onProgressUpdate方法 try { Thread.sleep(100);//耗時操作,如網(wǎng)絡(luò)請求 } catch (InterruptedException e) { e.printStackTrace(); } } return "執(zhí)行完畢"; } @Override protected void onProgressUpdate(Integer... values) { mProgressBar.setProgress(values[0]); super.onProgressUpdate(values); } @Override protected void onPostExecute(String s) { mTextView.setText(s); super.onPostExecute(s); } }
在Activity中創(chuàng)建我們新建的MAsyncTask實例并且執(zhí)行(無關(guān)代碼省略):
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { ... MAsyncTask asyncTask = new MAsyncTask(mTestPB, mTestTV); asyncTask.execute();//開始執(zhí)行 ... } }看看原理
在上面的代碼,我們開了個單一的線程來執(zhí)行了一個簡單的異步更新UI的操作(哈哈,可能會覺得AsyncTask有些大材小用了哈),現(xiàn)在來看看AsyncTask具體是怎么實現(xiàn)的,先從構(gòu)造方法開始:
public abstract class AsyncTask
AsyncTask為抽象類,并且有三個泛型,我覺得這三個泛型是很多使用者不懂的根源:
params:參數(shù),在execute() 傳入,可變長參數(shù),跟doInBackground(Void… params) 這里的params類型一致,我這里沒有傳參數(shù),所以可以將這個泛型設(shè)置為Void
Progress:執(zhí)行的進(jìn)度,跟onProgressUpdate(Integer… values) 的values的類型一致,一般情況為Integer
Result:返回值,跟String doInBackground 返回的參數(shù)類型一致,且跟onPostExecute(String s) 的s參數(shù)一致,在耗時操作執(zhí)行完畢調(diào)用。我這里執(zhí)行完畢返回了個字符串,所以為String
看了這三個泛型,我們就基本上了解了AsyncTask的執(zhí)行過程,主要就是上面代碼重寫的那幾個方法,現(xiàn)在來仔細(xì)看,首先在繼承AsyncTask時有個抽象方法必須重寫:
@WorkerThread protected abstract Result doInBackground(Params... params);
顧名思義,這個方法是在后臺執(zhí)行,也就是在子線程中執(zhí)行,需要子類來實現(xiàn),在這個方法里面我們可以調(diào)用publishProgress來發(fā)送進(jìn)度給UI線程,并且在onProgressUpdate方法中接收。
根據(jù)調(diào)用順序,我們一般會重寫這幾個方法:
//在doInBackground之前調(diào)用,在UI線程內(nèi)執(zhí)行 @MainThread protected void onPreExecute() { } //在執(zhí)行中,且在調(diào)用publishProgress方法時,在UI線程內(nèi)執(zhí)行,用于更新進(jìn)度 @MainThread protected void onProgressUpdate(Progress... values) { } //在doInBackground之后調(diào)用,在UI線程內(nèi)執(zhí)行 @MainThread protected void onPostExecute(Result result) { }
我們來看看這個publishProgress方法是怎么來調(diào)用onProgressUpdate方法的:
@WorkerThread protected final void publishProgress(Progress... values) { if (!isCancelled()) { getHandler().obtainMessage(MESSAGE_POST_PROGRESS, new AsyncTaskResult
使用obtainMessage是避免重復(fù)創(chuàng)建消息,調(diào)用了getHandler()然后發(fā)送消息,這里是一個單例
private static Handler getHandler() { synchronized (AsyncTask.class) { if (sHandler == null) { sHandler = new InternalHandler(); } return sHandler; } }
返回了一個InternalHandler:
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; } } }
在判斷消息為MESSAGE_POST_PROGRESS后我們發(fā)現(xiàn)其實內(nèi)部就是調(diào)用了Handler來實現(xiàn)這一切,包括執(zhí)行結(jié)束時調(diào)用finish方法,這個我們后面再說。從頭來看一下AsyncTask的執(zhí)行過程,來到execute方法:
/** This method must be invoked on the UI thread.(這行注釋為Google官方注釋) */ @MainThread public final AsyncTaskexecute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); }
注意!此方法必須在UI線程調(diào)用,這里就不做測試了。在這里又調(diào)用executeOnExecutor:
@MainThread public final AsyncTaskexecuteOnExecutor(Executor exec, Params... params) { ...... onPreExecute(); mWorker.mParams = params; exec.execute(mFuture); return this; }
我們發(fā)現(xiàn)在UI線程先調(diào)用了onPreExecute(),將傳入的參數(shù)賦值給mWorker.mParams,然后調(diào)用了參數(shù)exec的execute方法,并且將mFuture作為參數(shù)傳入,這里就設(shè)計到了三個對象:sDefaultExecutor(在executeOnExecutor中傳入)、mWorker、mFuture,來看看它們的賦值在哪里:
sDefaultExecutor:private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR; ...... public static final Executor SERIAL_EXECUTOR = new 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); } } }
我們發(fā)現(xiàn)sDefaultExecutor的賦值默認(rèn)就是SERIAL_EXECUTOR,也就是一個順序執(zhí)行的線程池,內(nèi)部實現(xiàn)有一個任務(wù)隊列。
mWorkerprivate final WorkerRunnablemWorker; 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); } }; ...... } private static abstract class WorkerRunnable implements Callable { Params[] mParams; }
在AsyncTask的構(gòu)造方法中,給mWorker賦值為一個Callable(帶返回參數(shù)的線程,涉及到j(luò)ava并發(fā)的一些基礎(chǔ)知識,這里不贅述),并且在call方法中執(zhí)行了doInBackground方法,最后調(diào)用postResult方法
mFutureprivate final FutureTaskmFuture; public AsyncTask() { ...... 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); } } }; }
mFuture為FutureTask類型,這里將mWorker傳入,在mWorker執(zhí)行完畢后調(diào)用postResultIfNotInvoked方法,我們先看看這個方法:
private void postResultIfNotInvoked(Result result) { final boolean wasTaskInvoked = mTaskInvoked.get(); if (!wasTaskInvoked) { postResult(result); } }
其實這個方法也最后調(diào)用了postResult,在這之前做了個有沒調(diào)用的判斷,確保任務(wù)執(zhí)行完畢后調(diào)用此方法。來看看postResult方法:
private Result postResult(Result result) { @SuppressWarnings("unchecked") Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult(this, result)); message.sendToTarget(); return result; }
又看到了熟悉的obtainMessage和sendToTarget發(fā)送消息,這次消息內(nèi)容變?yōu)?strong>MESSAGE_POST_RESULT,再來看看我們剛才已經(jīng)提到的InternalHandler的handleMessage方法:
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; } }
最后根據(jù)消息類型,這里調(diào)用了result.mTask.finish,result類型為AsyncTaskResult:
private static class AsyncTaskResult { final AsyncTask mTask; final Data[] mData; AsyncTaskResult(AsyncTask task, Data... data) { mTask = task; mData = data; } }
mTask的類型為AsyncTask,找到AsyncTask的finish方法:
private void finish(Result result) { if (isCancelled()) { onCancelled(result); } else { onPostExecute(result); } mStatus = Status.FINISHED; }
最后如果沒有取消的話調(diào)用了onPostExecute,也就是我們之前重寫的那個方法,在執(zhí)行完畢后調(diào)用,并且此方法也在子線程。
多線程并發(fā)正如開題所說,AsyncTask本質(zhì)上就是對Handler的封裝,在執(zhí)行之前,執(zhí)行中,執(zhí)行完畢都有相應(yīng)的方法,使用起來也一目了然,不過這還并不是AsyncTask的最大的優(yōu)點,AsyncTask最適合使用的場景是多線程,開始在代碼中已經(jīng)看到了在AsyncTask內(nèi)部有自己維護(hù)的線程池,默認(rèn)的是SERIAL_EXECUTOR
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
按照順序執(zhí)行,一個任務(wù)執(zhí)行完畢再執(zhí)行下一個,還提供有一個支持并發(fā)的線程池:
//獲取CPU數(shù)目 private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors(); //核心工作線程(同時執(zhí)行的線程數(shù)) private static final int CORE_POOL_SIZE = CPU_COUNT + 1; //線程池允許的最大線程數(shù)目 private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1; //空閑線程超時時間(單位為S) 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()); } }; //阻塞隊列,用來保存待執(zhí)行的任務(wù)(最高128個) private static final BlockingQueuesPoolWorkQueue = new LinkedBlockingQueue (128); public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
聲明為static,多個實例同用一個線程池,這個是Googl官方自帶的一個根據(jù)cpu數(shù)目來優(yōu)化的線程池,使用方法如下:
for(int i = 0; i < 100; i++) {//模擬100個任務(wù),不超過128 MAsyncTask asyncTask = new MAsyncTask(mTestPB, mTestTV); asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); }
在executeOnExecutor中我們還可以傳入自己自定義的線程池:
//跟默認(rèn)一樣的按順序執(zhí)行 asyncTask.executeOnExecutor(Executors.newSingleThreadExecutor()); //無限制的Executor asyncTask.executeOnExecutor(Executors.newCachedThreadPool()); //同時執(zhí)行數(shù)目為10的Executor asyncTask.executeOnExecutor(Executors.newFixedThreadPool(10));總結(jié)
AsyncTask使用起來的確很簡單方便,內(nèi)部也是Android的消息機(jī)制,并且很快捷的實現(xiàn)了異步更新UI,特別是多線程時也可以很好的表現(xiàn),這個是我們多帶帶使用Handler時不具備的,但是在使用過程中注意內(nèi)部方法的調(diào)用順序以及調(diào)用的時機(jī),比如asyncTask.execute() 要在UI主線程中調(diào)用,在子線程中調(diào)用是不可以的,還有就是在使用時根據(jù)情況來決定到底應(yīng)該用哪種線程池。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/70530.html
摘要:異步任務(wù)的構(gòu)造方法主要用于初始化線程池先關(guān)的成員變量創(chuàng)建一個新的異步任務(wù)。所以,我們是必須確保在銷毀活動之前取消任務(wù)。 目錄介紹 01.先看下AsyncTask用法 02.AsyncTask源碼深入分析 2.1 構(gòu)造方法源碼分析 2.2 看execute(Params... params)方法 2.3 mWorker和mFuture的創(chuàng)建過程 03.異步機(jī)制的實現(xiàn) 04.不同...
閱讀 2594·2023-04-26 03:00
閱讀 1408·2021-10-12 10:12
閱讀 4203·2021-09-22 15:33
閱讀 2930·2021-09-22 15:06
閱讀 1543·2019-08-30 15:44
閱讀 2155·2019-08-30 13:59
閱讀 543·2019-08-30 11:24
閱讀 2428·2019-08-29 17:07