Android Handler機(jī)制系列文章整體內(nèi)容如下:
- Android Handler機(jī)制1之Thread
- Android Handler機(jī)制2之ThreadLocal
- Android Handler機(jī)制3之SystemClock類
- Android Handler機(jī)制4之Looper與Handler簡(jiǎn)介
- Android Handler機(jī)制5之Message簡(jiǎn)介與消息對(duì)象對(duì)象池
- Android Handler機(jī)制6之MessageQueue簡(jiǎn)介
- Android Handler機(jī)制7之消息發(fā)送
- Android Handler機(jī)制8之消息的取出與消息的其他操作
- Android Handler機(jī)制9之Handler的Native實(shí)現(xiàn)前奏之Linux IO多路復(fù)用
- Android Handler機(jī)制10之Handdler的Native實(shí)現(xiàn)Native的實(shí)現(xiàn)
- Android Handler機(jī)制11之Handler機(jī)制總結(jié)
- Android Handler機(jī)制12之Callable、Future和FutureTask
- Android Handler機(jī)制13之AsyncTask源碼解析
本篇文章的主要內(nèi)容如下:
- 1法挨、AsyncTask概述
- 2初厚、基本用法
- 3峭弟、AsyncTask類源碼解析
- 4闷畸、AsyncTask類的構(gòu)造函數(shù)
- 5腰耙、AsyncTask類核心方法解析
- 6杠园、AsyncTask核心流程
- 7、AsyncTask與Handler
一掷邦、AsyncTask概述
我們都知道,Android UI線程是不安全的椭赋,如果想要在子線程里面進(jìn)行UI操作抚岗,就需要直接Android的異步消息處理機(jī)制,前面我寫了很多文章從源碼層面分析了Android異步消息Handler的處理機(jī)制哪怔。感興趣的可以去了解下宣蔚。不過為了更方便我們?cè)谧泳€程中更新UI元素,Android1.5版本就引入了一個(gè)AsyncTask類认境,使用它就可以非常靈活方便地從子線程切換到UI線程胚委。
二、基本用法
AsyncTask是一個(gè)抽象類叉信,我們需要?jiǎng)?chuàng)建子類去繼承它篷扩,并且重寫一些方法。AsyncTask接受三個(gè)泛型的參數(shù):
- Params:指定傳給任務(wù)執(zhí)行時(shí)的參數(shù)的類型
- Progress:指定后臺(tái)任務(wù)執(zhí)行時(shí)將任務(wù)進(jìn)度返回給UI線程的參數(shù)類型
- Result:指定任務(wù)完成后返回的結(jié)果類型
除了指定泛型參數(shù)茉盏,還需要根據(jù)重寫一些方法鉴未,常用的如下:
- onPreExecute():這個(gè)方法在UI線程調(diào)用,用于在任務(wù)執(zhí)行器那做一些初始化操作鸠姨,如在界面上顯示加載進(jìn)度空間
- onInBackground:在onPreExecute()結(jié)束之后立刻在后臺(tái)線程調(diào)用铜秆,用于耗時(shí)操作。在這個(gè)方法中可調(diào)用publishProgress方法返回任務(wù)的執(zhí)行進(jìn)度讶迁。
- onProgressUpdate:在doInBackground調(diào)用publishProgress后被調(diào)用连茧,工作在UI線程
- onPostExecute:后臺(tái)任務(wù)結(jié)束后被調(diào)用,工作在UI線程巍糯。
三啸驯、AsyncTask類源碼解析
(一)、類注釋翻譯
源碼注釋如下:
/**
* <p>AsyncTask enables proper and easy use of the UI thread. This class allows you
* to perform background operations and publish results on the UI thread without
* having to manipulate threads and/or handlers.</p>
*
* <p>AsyncTask is designed to be a helper class around {@link Thread} and {@link Handler}
* and does not constitute a generic threading framework. AsyncTasks should ideally be
* used for short operations (a few seconds at the most.) If you need to keep threads
* running for long periods of time, it is highly recommended you use the various APIs
* provided by the <code>java.util.concurrent</code> package such as {@link Executor},
* {@link ThreadPoolExecutor} and {@link FutureTask}.</p>
*
* <p>An asynchronous task is defined by a computation that runs on a background thread and
* whose result is published on the UI thread. An asynchronous task is defined by 3 generic
* types, called <code>Params</code>, <code>Progress</code> and <code>Result</code>,
* and 4 steps, called <code>onPreExecute</code>, <code>doInBackground</code>,
* <code>onProgressUpdate</code> and <code>onPostExecute</code>.</p>
*
* <div class="special reference">
* <h3>Developer Guides</h3>
* <p>For more information about using tasks and threads, read the
* <a href="{@docRoot}guide/components/processes-and-threads.html">Processes and
* Threads</a> developer guide.</p>
* </div>
*
* <h2>Usage</h2>
* <p>AsyncTask must be subclassed to be used. The subclass will override at least
* one method ({@link #doInBackground}), and most often will override a
* second one ({@link #onPostExecute}.)</p>
*
* <p>Here is an example of subclassing:</p>
* <pre class="prettyprint">
* 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");
* }
* }
* </pre>
*
* <p>Once created, a task is executed very simply:</p>
* <pre class="prettyprint">
* new DownloadFilesTask().execute(url1, url2, url3);
* </pre>
*
* <h2>AsyncTask's generic types</h2>
* <p>The three types used by an asynchronous task are the following:</p>
* <ol>
* <li><code>Params</code>, the type of the parameters sent to the task upon
* execution.</li>
* <li><code>Progress</code>, the type of the progress units published during
* the background computation.</li>
* <li><code>Result</code>, the type of the result of the background
* computation.</li>
* </ol>
* <p>Not all types are always used by an asynchronous task. To mark a type as unused,
* simply use the type {@link Void}:</p>
* <pre>
* private class MyTask extends AsyncTask<Void, Void, Void> { ... }
* </pre>
*
* <h2>The 4 steps</h2>
* <p>When an asynchronous task is executed, the task goes through 4 steps:</p>
* <ol>
* <li>{@link #onPreExecute()}, invoked on the UI thread before the task
* is executed. This step is normally used to setup the task, for instance by
* showing a progress bar in the user interface.</li>
* <li>{@link #doInBackground}, invoked on the background thread
* immediately after {@link #onPreExecute()} finishes executing. This step is used
* to perform background computation that can take a long time. The parameters
* of the asynchronous task are passed to this step. The result of the computation must
* be returned by this step and will be passed back to the last step. This step
* can also use {@link #publishProgress} to publish one or more units
* of progress. These values are published on the UI thread, in the
* {@link #onProgressUpdate} step.</li>
* <li>{@link #onProgressUpdate}, invoked on the UI thread after a
* call to {@link #publishProgress}. The timing of the execution is
* undefined. This method is used to display any form of progress in the user
* interface while the background computation is still executing. For instance,
* it can be used to animate a progress bar or show logs in a text field.</li>
* <li>{@link #onPostExecute}, invoked on the UI thread after the background
* computation finishes. The result of the background computation is passed to
* this step as a parameter.</li>
* </ol>
*
* <h2>Cancelling a task</h2>
* <p>A task can be cancelled at any time by invoking {@link #cancel(boolean)}. Invoking
* this method will cause subsequent calls to {@link #isCancelled()} to return true.
* After invoking this method, {@link #onCancelled(Object)}, instead of
* {@link #onPostExecute(Object)} will be invoked after {@link #doInBackground(Object[])}
* returns. To ensure that a task is cancelled as quickly as possible, you should always
* check the return value of {@link #isCancelled()} periodically from
* {@link #doInBackground(Object[])}, if possible (inside a loop for instance.)</p>
*
* <h2>Threading rules</h2>
* <p>There are a few threading rules that must be followed for this class to
* work properly:</p>
* <ul>
* <li>The AsyncTask class must be loaded on the UI thread. This is done
* automatically as of {@link android.os.Build.VERSION_CODES#JELLY_BEAN}.</li>
* <li>The task instance must be created on the UI thread.</li>
* <li>{@link #execute} must be invoked on the UI thread.</li>
* <li>Do not call {@link #onPreExecute()}, {@link #onPostExecute},
* {@link #doInBackground}, {@link #onProgressUpdate} manually.</li>
* <li>The task can be executed only once (an exception will be thrown if
* a second execution is attempted.)</li>
* </ul>
*
* <h2>Memory observability</h2>
* <p>AsyncTask guarantees that all callback calls are synchronized in such a way that the following
* operations are safe without explicit synchronizations.</p>
* <ul>
* <li>Set member fields in the constructor or {@link #onPreExecute}, and refer to them
* in {@link #doInBackground}.
* <li>Set member fields in {@link #doInBackground}, and refer to them in
* {@link #onProgressUpdate} and {@link #onPostExecute}.
* </ul>
*
* <h2>Order of execution</h2>
* <p>When first introduced, AsyncTasks were executed serially on a single background
* thread. Starting with {@link android.os.Build.VERSION_CODES#DONUT}, this was changed
* to a pool of threads allowing multiple tasks to operate in parallel. Starting with
* {@link android.os.Build.VERSION_CODES#HONEYCOMB}, tasks are executed on a single
* thread to avoid common application errors caused by parallel execution.</p>
* <p>If you truly want parallel execution, you can invoke
* {@link #executeOnExecutor(java.util.concurrent.Executor, Object[])} with
* {@link #THREAD_POOL_EXECUTOR}.</p>
*/
簡(jiǎn)單翻譯一下:
- AsyncTask可以輕松的正確使用UI線程祟峦,該類允許你執(zhí)行后臺(tái)操作并在UI線程更新結(jié)果罚斗,從而避免了無需使用Handler來操作線程
- AsyncTask是圍繞Thread與Handler而設(shè)計(jì)的輔助類,所以它并不是一個(gè)通用的線程框架宅楞。理想情況下针姿,AsyncTask應(yīng)該用于短操作(最多幾秒)。如果你的需求是在長(zhǎng)時(shí)間保持線程運(yùn)行厌衙,強(qiáng)烈建議您使用由
java.util.concurrent提供的各種API包距淫,比如Executor、ThreadPoolExecutor或者FutureTask婶希。- 一個(gè)異步任務(wù)被定義為:在后臺(tái)線程上運(yùn)行榕暇,并在UI線程更新結(jié)果。一個(gè)異步任務(wù)通常由三個(gè)類型:Params、Progress和Result彤枢。以及4個(gè)步驟:onPreExecute撤蟆、doInBackground、onProgressUpdate堂污、onPostExecute。
- 用法:AsyncTask必須由子類實(shí)現(xiàn)后才能使用龄砰,它的子類至少重寫doInBackground()這個(gè)方法盟猖,并且通常也會(huì)重寫onPostExecute()這個(gè)方法
- 下面是一個(gè)繼承AsyncTask類的一個(gè)子類的例子
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"); } }
一旦創(chuàng)建,任務(wù)會(huì)被很輕松的執(zhí)行换棚。就像下面這塊代碼一樣
new DownloadFilesTask().execute(url1,url2,url3);
- AsyncTask泛型式镐,在異步任務(wù)中通常有三個(gè)泛型
- Params:發(fā)送給任務(wù)的參數(shù)類型,這個(gè)類型會(huì)被任務(wù)執(zhí)行
- Progress:后臺(tái)線程進(jìn)度的計(jì)算的基本單位固蚤。
- Result:后臺(tái)線程執(zhí)行的結(jié)果類型娘汞。
- 如果異步任務(wù)不需要上面類型,則可以需要聲明類型未使用夕玩,通過使用Void來表示類型未使用你弦。就像下面一楊
private class MyTask extends AsyncTask<Void, Void, Void>{...}
- 四個(gè)步驟
- onPreExecute() 在執(zhí)行任務(wù)之前在UI線程上調(diào)用,此步驟通常用于初始化任務(wù)燎孟,例如在用戶界面顯示進(jìn)度條禽作。
- doInBackground() 方法在 onPreExecute()執(zhí)行完成后調(diào)用的。doInBackground()這個(gè)方法用于執(zhí)行可能需要很長(zhǎng)時(shí)間的首臺(tái)計(jì)算揩页。異步任務(wù)的參數(shù)被傳遞到這個(gè)步驟中旷偿。計(jì)算結(jié)果必須經(jīng)由這個(gè)步驟返回。這個(gè)步驟內(nèi)還可以調(diào)用publishProgress()方法發(fā)布一個(gè)或者多個(gè)進(jìn)度單位爆侣。在調(diào)用onProgressUpdate()函數(shù)后萍程,這個(gè)結(jié)果將在UI線程上更新。
- onProgressUpdate()方法:在調(diào)用publishProgress()之后在UI線程上調(diào)用兔仰。具體的執(zhí)行時(shí)間不確定茫负,該方法用于在后臺(tái)計(jì)算的異步任務(wù),把具體的進(jìn)度顯示在用戶界面乎赴。例如朽褪,它可以用于對(duì)進(jìn)度條進(jìn)行動(dòng)畫處理或者在文本字段中顯示日志。
- onPostExecute()方法无虚, 后臺(tái)任務(wù)完成后缔赠,在UI線程調(diào)用onPostExecute()方法,后臺(tái)運(yùn)行的結(jié)果作為參數(shù)傳遞給這個(gè)方法
- 取消任務(wù)
在任何時(shí)候都可以通過調(diào)用cancel(boolean)來取消任務(wù)友题。調(diào)用此方法將導(dǎo)致isCancelled()方法的后續(xù)調(diào)用返回true嗤堰。調(diào)用此方法后,在執(zhí)行doInBackground(Object [])方法后,將調(diào)用onCancelled(object)踢匣,而不是onPostExecute(Object)方法告匠。為了盡可能快的取消任務(wù),如果可能的話离唬,你應(yīng)該在調(diào)用doInBackground(Object[])之前檢查isCancelled()的返回值后专。- 線程規(guī)則,這個(gè)類必須遵循有關(guān)線程的一些規(guī)則才能正常使用输莺,規(guī)則如下:
- 必須在UI線程上加載AsyncTask類戚哎,android4.1上自動(dòng)完成
- 任務(wù)實(shí)例必須在UI線程上實(shí)例化
- execute()方法必須在主線程上調(diào)用
- 不要手動(dòng)去調(diào)用onPreExecute()、onPostExecute()嫂用、doInBackground()型凳、onProgressUpdate()方法。
- 這個(gè)任務(wù)只能執(zhí)行一次(如果嘗試第二次執(zhí)行嘱函,將會(huì)拋出異常)甘畅。
該任務(wù)只能執(zhí)行一次(如果嘗試第二次執(zhí)行,將拋出異常)往弓。- 內(nèi)存的觀察AsyncTask疏唾。保證所有回調(diào)調(diào)用都是同步的,使得以下操作在沒有顯示同步情況下是安全的函似。
- 在構(gòu)造函數(shù)或者onPreExecute設(shè)置成員變量荸实,并且在doInBackground()方法中引用它們。
- 在doInBackground()設(shè)置成員字段缴淋,并在onProgressUpdate()和onPostExecute()方法中引用他們准给。
- 執(zhí)行順序。第一引入AsyncTask時(shí)重抖,AsyncTasks是在單個(gè)后臺(tái)線程串行執(zhí)行的露氮。在android1.6以后,這被更改為允許多個(gè)任務(wù)并行操作的線程池钟沛。從android 3.0開始畔规,每個(gè)任務(wù)都是執(zhí)行在一個(gè)獨(dú)立的線程上,這樣可以避免一些并行執(zhí)行引起的常見的應(yīng)用程序錯(cuò)誤恨统。如果你想要并行執(zhí)行叁扫,可以使用THREAD_POOL_EXECUTOR來調(diào)用executeOnExecutor()方法。
至此這個(gè)類的注釋翻譯完畢畜埋,好長(zhǎng)啊莫绣,大家看完翻譯,是不是發(fā)現(xiàn)了很多之前沒有考慮到的問題悠鞍。
(二)对室、AsyncTask的結(jié)構(gòu)
AsyncTask的結(jié)構(gòu)如下:
我們看到在AsyncTask有4個(gè)自定義類,一個(gè)枚舉類,一個(gè)靜態(tài)塊掩宜,然后才是這個(gè)類的具體變量和屬性蔫骂,那我們就依次講解
(三)、枚舉Status
代碼在AsyncTask.java 256行
/**
* Indicates the current status of the task. Each status will be set only once
* during the lifetime of a task.
*/
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,
}
枚舉Status上的注釋翻譯一下就是:
Status表示當(dāng)前任務(wù)的狀態(tài)牺汤,每種狀態(tài)只能在任務(wù)的生命周期內(nèi)設(shè)置一次辽旋。
所以任務(wù)有三種狀態(tài)
- PENDING:表示任務(wù)尚未執(zhí)行的狀態(tài)
- RUNNING:表示任務(wù)正在執(zhí)行
- FINISHED:任務(wù)已完成
(四)、私有的靜態(tài)類InternalHandler
代碼在AsyncTask.java 656行
private static class InternalHandler extends Handler {
public InternalHandler() {
// 這個(gè)handler是關(guān)聯(lián)到主線程的
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;
}
}
}
通過上面的代碼我們知道:
- InternalHandler繼承自Handler檐迟,并且在它的構(gòu)造函數(shù)里面調(diào)用了Looper.getMainLooper()补胚,所以我們知道這個(gè)Handler是關(guān)聯(lián)主線程的。
- 重寫了handleMessage(Message)方法锅减,其中這個(gè)Message的obj這個(gè)類型是AsyncTaskResult(AsyncTaskResult我將在下面講解),然后根據(jù)msg.what的來區(qū)別伐坏。
- 我們知道這個(gè)Message只有兩個(gè)標(biāo)示怔匣,一個(gè)是MESSAGE_POST_RESULT代表消息的結(jié)果,一個(gè)是MESSAGE_POST_PROGRESS代表要執(zhí)行onProgressUpdate()方法桦沉。
通過這段代碼我們可以推測(cè)AsyncTask內(nèi)部實(shí)現(xiàn)線程切換每瞒,即切換到主線程是通過Handler來實(shí)現(xiàn)的。
(五)纯露、私有的靜態(tài)類AsyncTaskResult
代碼在AsyncTask.java 682行
@SuppressWarnings({"RawUseOfParameterizedType"})
private static class AsyncTaskResult<Data> {
final AsyncTask mTask;
final Data[] mData;
AsyncTaskResult(AsyncTask task, Data... data) {
mTask = task;
mData = data;
}
}
通過類名剿骨,我們大概可以推測(cè)出這一個(gè)負(fù)責(zé)AsyncTask結(jié)果的類
AsyncTaskResult這個(gè)類 有兩個(gè)成員變量,一個(gè)是AsyncTask一個(gè)是泛型的數(shù)組埠褪。
- mTask參數(shù):是為了AsyncTask是方便在handler的handlerMessage回調(diào)中方便調(diào)用AsyncTask的本身回調(diào)函數(shù)浓利,比如onPostExecute()函數(shù)、onPreogressUpdata()函數(shù)钞速,所以在AsyncTaskResult需要持有AsyncTask贷掖。
- mData參數(shù):既然是代表結(jié)果,那么肯定要有一個(gè)變量持有這個(gè)計(jì)算結(jié)果
(六)渴语、私有靜態(tài)抽象類WorkerRunnable
代碼在AsyncTask.java 677行
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
這個(gè)抽象類很簡(jiǎn)答苹威,首先是實(shí)現(xiàn)了Callable接口,然后里面有個(gè)變量
mParams驾凶,類型是泛型傳進(jìn)來的數(shù)組
(七)牙甫、局部變量詳解
AsyncTask的局部變量如下:
private static final String LOG_TAG = "AsyncTask";
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
// We want at least 2 threads and at most 4 threads in the core pool,
// preferring to have 1 less than the CPU count to avoid saturating
// the CPU with background work
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final int KEEP_ALIVE_SECONDS = 30;
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);
/**
* An {@link Executor} that can be used to execute tasks in parallel.
*/
public static final Executor THREAD_POOL_EXECUTOR;
/**
* An {@link Executor} that executes tasks one at a time in serial
* order. This serialization is global to a particular process.
*/
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();
那我們就來一一解答
- String LOG_TAG = "AsyncTask":打印專用
- CPU_COUNT = Runtime.getRuntime().availableProcessors():獲取當(dāng)前CPU的核心數(shù)
- CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4)):線程池的核心容量,通過代碼我們知道是一個(gè)大于等于2小于等于4的數(shù)
- MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1:線程池的最大容量是2倍的CPU核心數(shù)+1
- KEEP_ALIVE_SECONDS = 30:過剩的空閑線程的存活時(shí)間调违,一般是30秒
- sThreadFactory:線程工廠窟哺,通過new Thread來獲取新線程,里面通過使用AtomicInteger原子整數(shù)保證超高并發(fā)下可以正常工作技肩。
- sPoolWorkQueue:靜態(tài)阻塞式隊(duì)列脏答,用來存放待執(zhí)行的任務(wù),初始容量:128個(gè)
- THREAD_POOL_EXECUTOR:線程池
- SERIAL_EXECUTOR = new SerialExecutor():靜態(tài)串行任務(wù)執(zhí)行器,其內(nèi)部實(shí)現(xiàn)了串行控制殖告,循環(huán)的取出一個(gè)個(gè)任務(wù)交給上述的并發(fā)線程池去執(zhí)行阿蝶。
- MESSAGE_POST_RESULT = 0x1:消息類型,代表發(fā)送結(jié)果
- MESSAGE_POST_PROGRESS = 0x2:消息類型黄绩,代表進(jìn)度
- sDefaultExecutor = SERIAL_EXECUTOR:默認(rèn)任務(wù)執(zhí)行器羡洁,被賦值為串行任務(wù)執(zhí)行器,就是因?yàn)樗ぃ珹syncTask變成了串行的了筑煮。
- sHandler:靜態(tài)Handler,用來發(fā)送上面的兩種通知粤蝎,采用UI線程的Looper來處理消息真仲,這就是為什么AnsyncTask可以在UI線程更新UI
- WorkerRunnable<Params, Result> mWorke:是一個(gè)實(shí)現(xiàn)Callback的抽象類,擴(kuò)展了Callable多了一個(gè)Params參數(shù)初澎。
- mFuture:FutureTask對(duì)象
- mStatus = Status.PENDING:任務(wù)的狀態(tài)默認(rèn)為掛起秸应,即等待執(zhí)行,其類型標(biāo)示為volatile
- mCancelled = new AtomicBoolean():原子布爾類型碑宴,支持高并發(fā)訪問软啼,標(biāo)示任務(wù)是否被取消
- mTaskInvoked = new AtomicBoolean():原子布爾類型,支持高并發(fā)訪問延柠,標(biāo)示任務(wù)是否被執(zhí)行過
(八)祸挪、靜態(tài)代碼塊
代碼在AsyncTask.java 226行
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;
}
通過上面的(七)、局部變量詳解贞间,我們知道在靜態(tài)代碼塊中創(chuàng)建了一個(gè)線程池threadPoolExecutor贿条,并設(shè)置了核心線程會(huì)超時(shí)關(guān)閉,最后并把這個(gè)線程池指向THREAD_POOL_EXECUTOR增热。
(九)闪唆、私有的靜態(tài)類SerialExecutor
代碼在AsyncTask.java 226行
private static class SerialExecutor implements Executor {
// 循環(huán)數(shù)組實(shí)現(xiàn)的雙向Queue,大小是2的倍數(shù)钓葫,默認(rèn)是16悄蕾,有隊(duì)頭和隊(duì)尾巴兩個(gè)下標(biāo)
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
// 正在運(yùn)行runnable
Runnable mActive;
public synchronized void execute(final Runnable r) {
// 添加到雙向隊(duì)列中去
mTasks.offer(new Runnable() {
public void run() {
try {
//執(zhí)行run方法
r.run();
} finally {
//無論執(zhí)行結(jié)果如何都會(huì)取出下一個(gè)任務(wù)執(zhí)行
scheduleNext();
}
}
});
// 如果沒有活動(dòng)的runnable,則從雙端隊(duì)列里面取出一個(gè)runnable放到線程池中運(yùn)行
// 第一個(gè)請(qǐng)求任務(wù)過來的時(shí)候mActive是空的
if (mActive == null) {
//取出下一個(gè)任務(wù)來
scheduleNext();
}
}
protected synchronized void scheduleNext() {
//從雙端隊(duì)列中取出一個(gè)任務(wù)
if ((mActive = mTasks.poll()) != null) {
//線線程池執(zhí)行取出來的任務(wù)础浮,真正的執(zhí)行任務(wù)
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
- 首先帆调,注意SerialExecutor的execute是synchronized的,所以無論多個(gè)少任務(wù)調(diào)用execute()都是同步的豆同。
- 其次番刊,SerialExecutor里面一個(gè)ArrayDeque隊(duì)列,通過代碼我們知道影锈,SerialExecutor是通過ArrayDeque來管理Runnable對(duì)象的芹务。通過上面我們知道execute()是同步的蝉绷,所以如果你有10個(gè)任務(wù)同時(shí)調(diào)用SerialExecutor的execute()方法,就會(huì)把10個(gè)Runnable先后放入到mTasks中去枣抱,可見mTasks緩存了將要執(zhí)行的Runnable熔吗。
- 再次1,如果我們第一個(gè)執(zhí)行execute()方法時(shí)佳晶,會(huì)調(diào)用ArrayDeque的offer()方法將傳入的Runnable對(duì)象添加到隊(duì)列的尾部桅狠,然后判斷mActive是不是null,因?yàn)槭堑谝淮握{(diào)用轿秧,此時(shí)mActive還沒有賦值中跌,所以mActive等于null。所以此時(shí)mActive == null成立菇篡,所以會(huì)調(diào)用scheduleNext()方法漩符。
- 再次2,我們?cè)谡{(diào)用scheduleNext()里面驱还,看到會(huì)調(diào)用mTasks.poll()嗜暴,我們知道這是從隊(duì)列中取出頭部元素,然后把這個(gè)頭部元素賦值給mActive铝侵,然后讓THREAD_POOL_EXECUTOR這個(gè)線程池去執(zhí)行這個(gè)mActive的Runnable對(duì)象灼伤。
- 再次3触徐,如果這時(shí)候有第二個(gè)任務(wù)入隊(duì)咪鲜,但是此時(shí)mActive!=null,不會(huì)執(zhí)行scheduleNext()撞鹉,所以如果第一個(gè)任務(wù)比較耗時(shí)疟丙,后面的任務(wù)都會(huì)進(jìn)入隊(duì)列等待。
- 再次4鸟雏,上面知道由于第二個(gè)任務(wù)入隊(duì)后享郊,由于mActive!=null,所以不會(huì)執(zhí)行scheduleNext()孝鹊,那樣這樣后面的任務(wù)豈不是永遠(yuǎn)得不到處理炊琉,當(dāng)然不是,因?yàn)樵趏ffer()方法里面?zhèn)魅胍粋€(gè)Runnable的匿名類又活,并且在此使用了finnally代碼苔咪,意味著無論發(fā)生什么情況,這個(gè)finnally里面的代碼一定會(huì)執(zhí)行柳骄,而finnally代碼塊里面就是調(diào)用了scheduleNext()方法团赏,所以說每當(dāng)一個(gè)任務(wù)執(zhí)行完畢后,下一個(gè)任務(wù)才會(huì)執(zhí)行耐薯。
- 最后舔清,SerialExecutor其實(shí)模仿的是單一線程池的效果丝里,如果我們快速地啟動(dòng)了很多任務(wù),同一時(shí)刻只會(huì)有一個(gè)線程正在執(zhí)行体谒,其余的均處于等待狀態(tài)杯聚。
PS:scheduleNext()方法是synchronized,所以也是同步的
重點(diǎn)補(bǔ)充:
在Android 3.0 之前是并沒有SerialExecutor這個(gè)類的营密,那個(gè)時(shí)候是直接在AsyncTask中構(gòu)建一個(gè)sExecutor常量械媒,并對(duì)線程池總大小,同一時(shí)刻能夠運(yùn)行的線程數(shù)做了規(guī)定评汰,代碼如下:
private static final ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,
MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory);
四纷捞、AsyncTask類的構(gòu)造函數(shù)
代碼如下:
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*/
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
// 設(shè)置方法已經(jīng)被調(diào)用
mTaskInvoked.set(true);
// 設(shè)定結(jié)果變量
Result result = null;
try {
//設(shè)置線程優(yōu)先級(jí)
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
//執(zhí)行任務(wù)
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
// 產(chǎn)生異常則設(shè)置失敗
mCancelled.set(true);
throw tr;
} finally {
// 無論執(zhí)行成功還是出現(xiàn)異常,最后都會(huì)調(diào)用PostResult
postResult(result);
}
return result;
}
};
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
try {
// 就算沒有調(diào)用讓然去設(shè)置結(jié)果
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è)方法創(chuàng)建一個(gè)異步任務(wù)主儡,構(gòu)造函數(shù)必須在UI線程調(diào)用
這里面設(shè)計(jì)了兩個(gè)概念Callable和FutureTask蕴轨,如果大家對(duì)這兩個(gè)類有疑問云头,可以看我上一篇文章Android Handler機(jī)制12之Callable喂柒、Future和FutureTask
構(gòu)造函數(shù)也比較簡(jiǎn)單岗屏,主要就是給mWorker和mFuture初始化菠净,其中WorkerRunnable實(shí)現(xiàn)了Callable接口封恰,
在構(gòu)造函數(shù)里面調(diào)用了postResult(Result)和postResultIfNotInvoked(Result)西采,那我們就來分別看下
1美尸、postResult(Result)方法
// doInBackground執(zhí)行完畢捣染,發(fā)送消息
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
// 獲取一個(gè)Message對(duì)象
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
// 發(fā)送給線程
message.sendToTarget();
return result;
}
通過代碼我們知道
- 生成一個(gè)Message
- 把這個(gè)Message發(fā)送出
這里面調(diào)用了 getHandler()骄瓣,那我們來看下這個(gè)方法是怎么寫的
2、getHandler()方法
private static Handler getHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler();
}
return sHandler;
}
}
我們看到返回的是InternalHandler對(duì)象耍攘,上面說過了InternalHandler其實(shí)是關(guān)聯(lián)主線程的榕栏,所以上面方法 message.sendToTarget(); 其實(shí)是把消息發(fā)送給主線程。
大家注意一下 這里的Message的what值為MESSAGE_POST_RESULT蕾各,我們來看下InternalHandler遇到InternalHandler這種消息是怎么處理的
private static class InternalHandler extends Handler {
...
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;
...
}
}
}
我們看到MESSAGE_POST_RESULT對(duì)應(yīng)的是指是執(zhí)行AsyncTask的finish(Result)方法扒磁,所以我們可以這樣說,無論AsyncTask是成功了還是失敗了式曲,最后都會(huì)執(zhí)行finish(Result)方法妨托。那我們來看下finish(Result)方法里面都干了什么?
2.1吝羞、finish(Result result) 方法
private void finish(Result result) {
if (isCancelled()) {
// 如果消息取消了兰伤,執(zhí)行onCancelled方法
onCancelled(result);
} else {
// 如果消息沒有取消,則執(zhí)行onPostExecute方法
onPostExecute(result);
}
// 設(shè)置狀態(tài)值
mStatus = Status.FINISHED;
}
注釋寫的很清楚了脆贵,我這里就不說明了医清,通過上面的代碼和finish方法的分析,我們知道無論成功還是失敗卖氨,最后一定會(huì)調(diào)用finish(Result)方法会烙,所以最后狀態(tài)的值為FINISHED负懦。
3、postResultIfNotInvoked(Result)方法
private void postResultIfNotInvoked(Result result) {
// 獲取mTaskInvoked的值
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result);
}
}
通過上面代碼我們知道柏腻,如果mTaskInvoked不為true纸厉,則執(zhí)行postResult,但是在mWorker初始化的時(shí)候?yàn)閠rue五嫂,除非在沒有執(zhí)行call方法時(shí)候颗品,如果沒有執(zhí)行call,說明這個(gè)異步線程還沒有開始執(zhí)行沃缘,這個(gè)時(shí)候mTaskInvoked為false躯枢。而這時(shí)候調(diào)用postResultIfNotInvoked則還是會(huì)執(zhí)行postResult(Result),這樣保證了AsyncTask一定有返回值槐臀。
五锄蹂、AsyncTask類核心方法解析
(一)、void onPreExecute()
/**
* Runs on the UI thread before {@link #doInBackground}.
*
* @see #onPostExecute
* @see #doInBackground
*/
// 在調(diào)用doInBackground()方法之前水慨,跑在主線程上
@MainThread
protected void onPreExecute() {
}
其實(shí)注釋很清楚了得糜,在task任務(wù)開始執(zhí)行的時(shí)候在主線程調(diào)用,在doInBackground(Params… params) 方法之前調(diào)用晰洒。
(二)朝抖、AsyncTask<Params, Progress, Result> onPreExecute() 方法
/**
* Executes the task with the specified parameters. The task returns
* itself (this) so that the caller can keep a reference to it.
*
* <p>Note: this function schedules the task on a queue for a single background
* thread or pool of threads depending on the platform version. When first
* introduced, AsyncTasks were executed serially on a single background thread.
* Starting with {@link android.os.Build.VERSION_CODES#DONUT}, this was changed
* to a pool of threads allowing multiple tasks to operate in parallel. Starting
* {@link android.os.Build.VERSION_CODES#HONEYCOMB}, tasks are back to being
* executed on a single thread to avoid common application errors caused
* by parallel execution. If you truly want parallel execution, you can use
* the {@link #executeOnExecutor} version of this method
* with {@link #THREAD_POOL_EXECUTOR}; however, see commentary there for warnings
* on its use.
*
* <p>This method must be invoked on the UI thread.
*
* @param params The parameters of the task.
*
* @return This instance of AsyncTask.
*
* @throws IllegalStateException If {@link #getStatus()} returns either
* {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
*
* @see #executeOnExecutor(java.util.concurrent.Executor, Object[])
* @see #execute(Runnable)
*/
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
首先來翻譯一下注釋
- 使用指定的參數(shù)來執(zhí)行任務(wù),這個(gè)方法的返回值是this谍珊,也就是它自己治宣,因?yàn)檫@樣設(shè)計(jì)的目的是可以保持對(duì)它的引用。
- 注意:它的調(diào)度模式是不同的抬驴,一種是單個(gè)后臺(tái)線程炼七,一種是通過線程池來實(shí)現(xiàn)缆巧,具體那種模式是根據(jù)android版本的不同而不同布持,當(dāng)最開始引入AsyncTask的時(shí)候,AsyncTask是單個(gè)后臺(tái)線程上串行執(zhí)行陕悬,從Android DONUT 開始题暖,模式變更為通過線程池多任務(wù)并行執(zhí)行。在Android HONEYCOMB開始捉超,又變回了在單個(gè)線程上執(zhí)行胧卤,這樣可以避免并行執(zhí)行的錯(cuò)誤。如果你還是想并行執(zhí)行拼岳,你可以使用executeOnExecutor()方法并且第一個(gè)參數(shù)是THREAD_POOL_EXECUTOR就可以了枝誊,不過,請(qǐng)注意有關(guān)使用警告惜纸。
- 必須在UI主線程上調(diào)用此方法叶撒。
通過代碼我們看到绝骚,它的內(nèi)部其實(shí)是調(diào)用executeOnExecutor(Executor exec, Params... params)方法,只不過第一個(gè)參數(shù)傳入的是sDefaultExecutor祠够,而sDefaultExecutor是SerialExecutor的對(duì)象压汪。上面我們提到了SerialExecutor里面利用ArrayDeque來實(shí)現(xiàn)串行的,所以我們可以推測(cè)出如果在executeOnExecutor(Executor exec, Params... params)方法里面如果第一個(gè)參數(shù)是自定義的Executor古瓤,AsyncTask就可以實(shí)現(xiàn)并發(fā)執(zhí)行止剖。
(三)、executeOnExecutor(Executor exec, Params... params) 方法
/**
* Executes the task with the specified parameters. The task returns
* itself (this) so that the caller can keep a reference to it.
*
* <p>This method is typically used with {@link #THREAD_POOL_EXECUTOR} to
* allow multiple tasks to run in parallel on a pool of threads managed by
* AsyncTask, however you can also use your own {@link Executor} for custom
* behavior.
*
* <p><em>Warning:</em> Allowing multiple tasks to run in parallel from
* a thread pool is generally <em>not</em> what one wants, because the order
* of their operation is not defined. For example, if these tasks are used
* to modify any state in common (such as writing a file due to a button click),
* there are no guarantees on the order of the modifications.
* Without careful work it is possible in rare cases for the newer version
* of the data to be over-written by an older one, leading to obscure data
* loss and stability issues. Such changes are best
* executed in serial; to guarantee such work is serialized regardless of
* platform version you can use this function with {@link #SERIAL_EXECUTOR}.
*
* <p>This method must be invoked on the UI thread.
*
* @param exec The executor to use. {@link #THREAD_POOL_EXECUTOR} is available as a
* convenient process-wide thread pool for tasks that are loosely coupled.
* @param params The parameters of the task.
*
* @return This instance of AsyncTask.
*
* @throws IllegalStateException If {@link #getStatus()} returns either
* {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
*
* @see #execute(Object[])
*/
@MainThread
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)");
}
}
//設(shè)置狀態(tài)
mStatus = Status.RUNNING;
從這里我們看出onPreExecute是先執(zhí)行落君,并且在UI線程
onPreExecute();
// 設(shè)置參數(shù)
mWorker.mParams = params;
// 開啟了后臺(tái)線程去計(jì)算穿香,這是真正調(diào)用doInBackground的地方
exec.execute(mFuture);
// 接著會(huì)有onProgressUpdate會(huì)被調(diào)用,最后是onPostExecute
return this;
}
老規(guī)矩 先翻譯一下注釋:
- 使用指定的參數(shù)來執(zhí)行任務(wù)绎速,這個(gè)方法的返回值是this扔水,也就是它自己,因?yàn)檫@樣設(shè)計(jì)的目的是可以保持對(duì)它的引用朝氓。
- 這個(gè)方法通常與THREAD_POOL_EXECUTOR一起使用魔市,這樣可以讓多個(gè)人物在AsyncTask管理的線程池上并行運(yùn)行,但你也可以使用自定義的Executor赵哲。
- 警告:由于大多數(shù)情況并沒有定義任務(wù)的操作順序待德,所以在線程池中多任務(wù)并行并不常見。例如:如果修改共同狀態(tài)的任務(wù)(就像點(diǎn)擊按鈕就可以編寫文件)枫夺,對(duì)修改的順訊沒有保證将宪。在很少的情況下,如果沒有仔細(xì)工作橡庞,較新版本的數(shù)據(jù)可能會(huì)被較舊的數(shù)據(jù)覆蓋较坛,從而導(dǎo)致數(shù)據(jù)丟失和穩(wěn)定性問題。而這些變更最好是連續(xù)執(zhí)行扒最,因?yàn)檫@樣可以保證工作的有序化丑勤,無論平臺(tái)版本如何,你可以使用SERIAL_EXECUTOR吧趣。
- 必須在UI主線程上調(diào)用此方法法竞。
- 參數(shù)exec:為了實(shí)現(xiàn)輕松解耦,我們可以使用THREAD_POOL_EXECUTOR這個(gè)線程池可以作為合適的進(jìn)程范圍的線程池
- 參數(shù)params:任務(wù)的參數(shù)
那我們來看下一下代碼强挫,代碼里面的邏輯如下:
- 該方法首先是判斷mStatus狀態(tài)岔霸,如果是正在運(yùn)行(RUNNING)或者已經(jīng)結(jié)束(FINISHED),就會(huì)拋出異常俯渤。
- 接著設(shè)置狀態(tài)為RUNNING呆细,即運(yùn)行,執(zhí)行onPreExecute()方法八匠,并把參數(shù)的值賦給mWorker.mParams
- 于是Executor去執(zhí)行execute的方法絮爷,學(xué)過Java多線程的都知道诡曙,這里方法是開啟一個(gè)線程去執(zhí)行mFuture的run()方法(由于mFuture用Callable構(gòu)造,所以其實(shí)是執(zhí)行的Callable的call()方法略水,而mWorker是Callable的是實(shí)現(xiàn)類价卤,所以最終執(zhí)行的是mWorker的call()方法)
PS:mFuture和mWorker都是在AsyncTask的構(gòu)造方法中初始化過的。
(四)渊涝、 publishProgress(Progress... values) 方法
主要是設(shè)置后臺(tái)進(jìn)度慎璧,onProgressUpdate會(huì)被調(diào)用
/**
* This method can be invoked from {@link #doInBackground} to
* publish updates on the UI thread while the background computation is
* still running. Each call to this method will trigger the execution of
* {@link #onProgressUpdate} on the UI thread.
*
* {@link #onProgressUpdate} will not be called if the task has been
* canceled.
*
* @param values The progress values to update the UI with.
*
* @see #onProgressUpdate
* @see #doInBackground
*/
@WorkerThread
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
這個(gè)方法內(nèi)部實(shí)現(xiàn)很簡(jiǎn)單
- 首先判斷 任務(wù)是否已經(jīng)被取消,如果已經(jīng)被取消了跨释,則什么也不做
- 如果任務(wù)沒有被取消胸私,則通過InternalHandler發(fā)送一個(gè)what為MESSAGE_POST_PROGRESS的Message
這樣就進(jìn)入了InternalHandler的handleMessage(Message)里面了,而我們知道InternalHandler的Looper是Looper.getMainLooper()鳖谈,所以處理Message是在主線程中岁疼,我們來看下代碼
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;
}
}
}
通過代碼,我們看到如果what為MESSAGE_POST_PROGRESS缆娃,則會(huì)在主線程中調(diào)用onProgressUpdate(result.mData)捷绒,這也就是為什么我們平時(shí)在異步線程調(diào)用publishProgress(Progress...)方法后,可以在主線程中的onProgressUpdate(rogress... values)接受數(shù)據(jù)了贯要。
六暖侨、AsyncTask核心流程
其實(shí)在上面講解過程中,我基本上已經(jīng)把整體流程講解過了崇渗,我這里補(bǔ)上一張圖字逗,比較全面的闡述了AsyncTask的執(zhí)行流程如下:
對(duì)應(yīng)的時(shí)序圖如下:
大家如果手機(jī)上看不清,我建議down下來在電腦上看宅广。
如果結(jié)合AsyncTask的狀態(tài)值葫掉,流程圖如下:
如果把AsyncTask和Handler分開則流程圖如下:
最后如果把AsyncTask里面所有類的涉及關(guān)系整理如下圖:
七、AsyncTask與Handler
- AsyncTask:
- 優(yōu)點(diǎn):AsyncTask是一個(gè)輕量級(jí)的異步任務(wù)處理類跟狱,輕量級(jí)體現(xiàn)在俭厚,使用方便,代碼簡(jiǎn)潔兽肤,而且整個(gè)異步任務(wù)的過程可以通過cancel()進(jìn)行控制
- 缺點(diǎn):不適用處理長(zhǎng)時(shí)間的異步任務(wù)套腹,一般這個(gè)異步任務(wù)的過程最好控制在幾秒以內(nèi)绪抛,如果是長(zhǎng)時(shí)間的異步任務(wù)就需要考慮多線程的控制問題资铡;當(dāng)處理多個(gè)異步任務(wù)時(shí),UI更新變得困難幢码。
- Handler:
- 優(yōu)點(diǎn):代碼結(jié)構(gòu)清晰笤休,容易處理多個(gè)異步任務(wù)
- 缺點(diǎn):當(dāng)有多個(gè)異步任務(wù)時(shí),由于要配合Thread或Runnable症副,代碼可能會(huì)稍顯冗余店雅。
總之政基,AsyncTask不失為一個(gè)非常好用的異步任務(wù)處理類。不過我從事Android開發(fā)5年多了闹啦,很少會(huì)用到AsyncTask沮明,一般異步任務(wù)都是Handler。