多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內(nèi)最全I(xiàn)T社區(qū)平臺 聯(lián)系我們 | 收藏本站
阿里云優(yōu)惠2
您當(dāng)前位置:首頁 > php開源 > 綜合技術(shù) > Android AsyncTask 從源碼角度解析其原理和用法

Android AsyncTask 從源碼角度解析其原理和用法

來源:程序員人生   發(fā)布時間:2015-06-16 08:15:26 閱讀次數(shù):2685次

AsyncTask 在線查看源碼地址:AsyncTask源碼查看

AsyncTask簡介:

盡人皆知知道,Android UI是線程不安全的,如果要想在子線程中更新UI操作,必須使用Android的異步消息處理機(jī)制。固然我們自己可以實現(xiàn)1個Handler+Message消息處理機(jī)制來在子線程中更新UI操作。有時候覺得自己寫這個異步消息處理機(jī)制很麻煩有木有??不過慶幸的是,Android 給我們實現(xiàn)了這么1套異步消息處理機(jī)制,我們直接拿來用就是了,從而 AsyncTask就誕生了。AsyncTask用于Android的異步消息 處理機(jī)制,來實現(xiàn)子線程和UI線程間的1些通訊。

AsyncTask的基本用法:

官網(wǎng)給了個很好的例子:

private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> { protected Long doInBackground(URL... urls) { int count = urls.length; long totalSize = 0; for (int i = 0; i < count; i++) { totalSize += Downloader.downloadFile(urls[i]); publishProgress((int) ((i / (float) count) * 100)); // Escape early if cancel() is called if (isCancelled()) break; } return totalSize; } protected void onProgressUpdate(Integer... progress) { setProgressPercent(progress[0]); } protected void onPostExecute(Long result) { showDialog("Downloaded " + result + " bytes"); } }





履行操作以下:
new DownloadFilesTask().execute(url1, url2, url3);




由于AsyncTask是個抽象類,如果我們要使用它,必須寫個子類去繼承AsyncTask,在繼承時我們可以為AsyncTask類指定3個泛型參數(shù),這3個參數(shù)的用處以下:
1.Params:
用于 doInBackground()后臺履行任務(wù)的參數(shù)。

2.Progress:
用于后臺履行任務(wù)進(jìn)度的更新。

3.Result:
當(dāng)任務(wù)履行終了時,需要對結(jié)果進(jìn)行返回,用于保存履行結(jié)果。

AsyncTask履行的步驟以下:
onPreExecute():在UI線程中履行,通經(jīng)常使用于異步任務(wù)履行之前,初始化1些數(shù)據(jù),比如:初始化進(jìn)度條等。

doInBackground(java.lang.Object[]):在后臺線程中履行,1般耗時任務(wù)都在這個方法里面實現(xiàn),固然在這個方法里面我們必須返回履行結(jié)果,用于onPostExecute(java.lang.Object)步驟,將異步任務(wù)結(jié)果發(fā)布到UI線程中。在這個方法里我們可以選擇性的調(diào)用publishProgress(java.lang.Object[])方法,用于將異步任務(wù)履行進(jìn)度信息發(fā)布到UI線程中。

onProgressUpdate(java.lang.Object[]):在UI線程中履行,用于對后臺任務(wù)履行進(jìn)度信息的更新。只有在doInBackground(java.lang.Object[])方法中調(diào)用了publishProgress(java.lang.Object[])方法,才能拿到后臺任務(wù)履行進(jìn)度信息。

onPostExecute(java.lang.Object):在UI線程中履行,用于獲得后臺任務(wù)履行的結(jié)果。



AsyncTask的特點

1.異步任務(wù)的實例必須在UI線程中創(chuàng)建
2.execute(Params... params)方法履行必須在UI線程中調(diào)用
3.1個異步任務(wù)只能履行1個,不然會拋出“Cannot execute task:the task is already running.”異常。
4.不能在doInBackground 做更新UI的操作。
5.不要手動的去調(diào)用onPreExecute(),doInBackground(Params... params),onProgressUpdate(Progress... values),onPostExecute(Result result) 這幾個方法

解析以上5點Why??等我們分析完全個源碼再來回答這個問題吧。

AsycnTask的源碼分析

1.execute(params)

public final AsyncTask<Params, Progress, Result> execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); }


這個方法只履行了1行代碼,就是調(diào)用executeOnExecutor(sDefaultExecutor, params) 方法。進(jìn)去看看:
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; }

我們可以看到這里有個狀態(tài)值的判斷,就是枚舉類型Status了,看看代碼:
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. */ FINISHED, }
3種狀態(tài)用來標(biāo)志當(dāng)前的異步任務(wù)處于那種狀態(tài)。當(dāng)前任務(wù)的初始狀態(tài)是PENDING:為待履行狀態(tài)。

接著我們回到
executeOnExecutor方法中
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; }
第1個任務(wù)履行,第 3 行的if條件不滿足,那末第15行重新標(biāo)記當(dāng)前任務(wù)狀態(tài)為正在履行。第17行調(diào)用 onPreExcute()方法,在UI線程中我們可以重寫此方法用于履行異步任務(wù)之前的1些準(zhǔn)備工作。第20行是exec線程池真正履行后臺耗時任務(wù)mFuture的地方。mFuture就是實例化AsyncTask對象的時候取得。exec是外部傳入的參數(shù),該參數(shù)在實例化的時候默許是sDefaultExecutor順序履行的線程池。

看代碼你會發(fā)現(xiàn),當(dāng)同1個任務(wù)被履行兩次的話,第 3 行的if條件就滿足了,自然就會拋出相應(yīng)的異常,這里就解釋了AsyncTask特點的第3點,同1個任務(wù)不能被履行兩次以上。


2.我們來看看AsyncTask實例化的代碼


public AsyncTask() { mWorker = new WorkerRunnable<Params, Result>() { public Result call() throws Exception { mTaskInvoked.set(true); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //noinspection unchecked return postResult(doInBackground(mParams)); } }; 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 occured while executing doInBackground()", e.getCause()); } catch (CancellationException e) { postResultIfNotInvoked(null); } } }; }

看著代碼這么長,其實就初始化了兩個變量,第1個變量是mWorker,第2個變量mFuture。
1.mWorker:是1個內(nèi)部接口類對象,實現(xiàn)了里面的call()方法,call()方法里調(diào)用了
doInBackground(mParams)方法。什么時候調(diào)用mWorker.call()方法?我們發(fā)現(xiàn) mWorker作為參數(shù)用作第2個變量mFuture的獲得。
2.mFuture:是1個線程接口類對象,run()方法里面調(diào)用了mWorker.call()方法,具體怎樣調(diào)用就不屬于AsyncTask類的范圍了。</span>
總結(jié):其實實例化對象的時候只要記住我們持有了mFuture對象,里面回調(diào)了done()方法,回調(diào)里面僅僅是調(diào)用了postResultIfNotInvoked(get())方法。進(jìn)入看看</span>
private void postResultIfNotInvoked(Result result) { final boolean wasTaskInvoked = mTaskInvoked.get(); if (!wasTaskInvoked) { postResult(result); } } private Result postResult(Result result) { @SuppressWarnings("unchecked") Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(this, result)); message.sendToTarget(); return result; }



代碼10⑴2行可以看出,這里用Handler+Message消息處理機(jī)制將 異步任務(wù)履行結(jié)果發(fā)布到UI線程中,看看sHandler怎樣實現(xiàn)的吧?
protected final void publishProgress(Progress... values) { if (!isCancelled()) { sHandler.obtainMessage(MESSAGE_POST_PROGRESS, new AsyncTaskResult<Progress>(this, values)).sendToTarget(); } } private void finish(Result result) { if (isCancelled()) { onCancelled(result); } else { onPostExecute(result); } mStatus = Status.FINISHED; } private static class InternalHandler extends Handler { @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; } } }




這是1個靜態(tài)內(nèi)部類,在取得不同消息做不同處理,MESSAGE_POST_RESULT:消息調(diào)用 mTask.finish()。代碼在第 8 行實現(xiàn)了,該方法里面調(diào)用了
onPostExecute(result)
將異步履行任務(wù)發(fā)布到UI線程中,并且在第 14 行改變當(dāng)前任務(wù)的履行狀態(tài)為finished。  MESSAGE_POST_PROGRESS:消息調(diào)用了 mTask.onProgressUpdate().用于發(fā)布任務(wù)履行進(jìn)度到UI線程中。

這里我們可以看出,AsyncTask 自己內(nèi)部實現(xiàn)了1個 內(nèi)部的 Handler + Message + Thread 消息處理機(jī)制用于履行耗時任務(wù)更新UI操作等。 我們會發(fā)現(xiàn)InternalHandler的申明實在類加載的時候就實現(xiàn)了,代碼:

private static final InternalHandler sHandler = new InternalHandler();


由于我們的Handler+Message消息處理機(jī)制是對用于UI線程的通知,基于消息是誰發(fā)送誰處理原理,我們的Handler必須是在UI線程中申明,也就是說,只有UI線程持有Handler的對象發(fā)送的消息才可以在UI線程中獲得到這個消息。因此我們就能夠解釋AsyncTask特點的第1點:異步任務(wù)的實例必須在UI線程中創(chuàng)建


至此 AsyncTask履行基本結(jié)束。

3.總結(jié): 客戶端調(diào)用execute()方法,先履行 onPreExecute()方法,然后通過線程池sDefaultExecutor 履行1個 mFuture異步任務(wù),在這個進(jìn)程中 調(diào)用doBackground方法履行后天任務(wù),然后通過InternalHandler 消息處理機(jī)制將后臺履行的結(jié)果通過 onPostExecute()方法發(fā)布給UI線程。由于onPreExecute()方法的運行是在后臺任務(wù)履行前運行,所以 execute()必須在 UI線程中調(diào)用。這就解釋了 AsyncTask特點的第2點:execute(Params... params)方法履行必須在UI線程中調(diào)用。


注意:我么這里還有1個問題:最新版本的AsyncTask 是順序履行異步任務(wù)的,也就是說只有第1個任務(wù)履行完成以后才能履行第2條任務(wù),為何會這樣呢?還是從源碼中找答案吧。AsyncTask 使用的默許線程池是 sDefaultExecutor,看代碼實現(xiàn):

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 final InternalHandler sHandler = new InternalHandler(); private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR; 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 { final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>(); 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); } } }


AsyncTask 內(nèi)部實現(xiàn)了1個順序履行的線程池,那末如果我們想要并發(fā)履行異步任務(wù)該怎樣辦呢?不用著急, AsyncTask 給你留了1個后門,我們使用 AsyncTask 1般都是調(diào)用 execute(params)方法, 其實你會發(fā)現(xiàn) execute 也是調(diào)用 executeOnExecutor方法的,只是參數(shù)使用的是默許sDefaultExecutor,所以我們可以 自己直接調(diào)用executeOnExecutor方法,然后自定義1個 并發(fā)的線程池作為參數(shù)傳入。比例我們可以這么調(diào)用:

ExecutorService executorService = Executors.newCachedThreadPool(); asyncTask.executeOnExecutor(executorService,params);


那末這個任務(wù)就是并發(fā)的了。


生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對您的學(xué)習(xí)有所幫助,可以手機(jī)掃描二維碼進(jìn)行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關(guān)閉
程序員人生
主站蜘蛛池模板: 国产91久久精品一区二区 | 老司机午夜精品视频在线观看免费 | 国产美女久久久久久久久久久 | 一级在线毛片 | 中国美女隐私无遮挡免费视频 | 欧美成人性生活视频 | 国语精品91自产拍在线观看二区 | 久草精品视频在线观看 | 国产日韩精品欧美一区喷 | 亚洲第一黄色网 | 99热这里有精品 | 成人在线精品视频 | 在线国产中文字幕 | 一区二区免费视频 | 日本香蕉一区二区三区 | 欧美人善交vides0 | 日本欧美一区二区三区视频麻豆 | 亚洲女人天堂 | 亚洲精品国产一区二区三 | 久久久久久国产精品三级 | 青青自拍视频一区二区三区 | 亚洲精品亚洲人成在线播放 | 久久精品免视看国产明星 | 欧美激情福利视频在线观看免费 | 久久最新网址 | 九九精品视频一区二区三区 | 日本一区二区三区四区五区 | 亚洲免费闲人蜜桃 | 天天综合久久久网 | 中文字幕一区精品欧美 | jizz在线观看国产精品 | 国产精品一区伦免视频播放 | 亚洲一级高清在线中文字幕 | 日韩另类| 麻豆精品不卡国产免费看 | 欧美日本韩国一区 | 最近的中文字幕视频完整 | 18jlzz大全| 性欧美videofree中文字幕 | japanese18—23护士| 亚洲国产精品久久卡一 |