Android 中線程可分為主線程
和子線程
兩類(lèi)辙纬,其中主線程也就是UI線程
瓷马,它的主要這作用就是運(yùn)行四大組件、處理界面交互膝宁。子線程則主要是處理耗時(shí)任務(wù)鸦难,也是我們要重點(diǎn)分析的。
首先 Java 中的各種線程在 Android 里是通用的员淫,Android 特有的線程形態(tài)也是基于 Java 的實(shí)現(xiàn)的合蔽,所以有必要先簡(jiǎn)單的了解下 Java 中的線程,本文主要包括以下內(nèi)容:
- Thread介返、Runnable
- Callable拴事、Future
- 線程池
- IntentService、HandlerThread
- AsyncTask
一圣蝎、Thread刃宵、Runnable
在 Java 中要?jiǎng)?chuàng)建子線程可以直接繼承Thread
類(lèi),重寫(xiě)run()
方法:
public class MyThread extends Thread {
@Override
public void run() {
}
}
// 啟動(dòng)線程
new MyThread().start();
或者實(shí)現(xiàn)Runnable
接口徘公,然后用Thread執(zhí)行Runnable牲证,這種方式比較常用:
public class MyRunnable implements Runnable {
@Override
public void run() {
}
}
// 啟動(dòng)線程
new Thread(new MyRunnable()).start();
簡(jiǎn)單的總結(jié)下:
- Runnable 可以實(shí)現(xiàn)多個(gè)線程共享資源,可以參考網(wǎng)上賣(mài)票的例子
- Runnable 可以避免 Java 中的單繼承的限制
- 無(wú)法直接得到任務(wù)的執(zhí)行結(jié)果
二关面、Callable坦袍、Future
Callable
和Runnable
類(lèi)似,都可以用來(lái)處理具體的耗時(shí)任務(wù)邏輯的缭裆,但是但具體的差別在哪里呢键闺?看一個(gè)小例子:
定義 MyCallable 實(shí)現(xiàn)了 Callable
接口,和之前Runnable
的run()
方法對(duì)比下澈驼,call()
方法是有返回值的哦辛燥,泛型就是返回值的類(lèi)型:
public class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
Log.e("call", "task start");
Thread.sleep(2000);
Log.e("call", "task finish");
return "hello thread";
}
}
一般會(huì)通過(guò)線程池來(lái)執(zhí)行Callable
(線程池相關(guān)內(nèi)容后邊會(huì)講到),執(zhí)行結(jié)果就是一個(gè)Future
對(duì)象:
// 創(chuàng)建一個(gè)線程池
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
// 執(zhí)行任務(wù)
Future<String> result = cachedThreadPool.submit(new MyCallable());
try {
// 獲取執(zhí)行結(jié)果
Log.e("result", result.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
可以看到,通過(guò)線程池執(zhí)行 MyCallable 對(duì)象返回了一個(gè) Future
對(duì)象挎塌,取出執(zhí)行結(jié)果徘六。
Future
是一個(gè)接口,從其內(nèi)部的方法可以看出它提供了取消任務(wù)(有坑A穸肌4狻!)嘴高、判斷任務(wù)是否完成竿音、獲取任務(wù)結(jié)果的功能:
public interface Future<V> {
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
Future
接口有一個(gè)FutureTask
實(shí)現(xiàn)類(lèi),同時(shí)FutureTask
也實(shí)現(xiàn)了Runnable
接口拴驮,并提供了兩個(gè)構(gòu)造函數(shù):
public FutureTask(Callable<V> callable) {
}
public FutureTask(Runnable runnable, V result) {
}
用FutureTask
一個(gè)參數(shù)的構(gòu)造函數(shù)來(lái)改造下上邊的例子:
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
FutureTask<String> futureTask = new FutureTask<>(new MyCallable());
cachedThreadPool.submit(futureTask);
try {
Log.e("result", futureTask.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
FutureTask
內(nèi)部有一個(gè)done()
方法春瞬,代表Callable
中的任務(wù)已經(jīng)結(jié)束,可以用來(lái)獲取執(zhí)行結(jié)果:
FutureTask<String> futureTask = new FutureTask<String>(new MyCallable()){
@Override
protected void done() {
super.done();
try {
Log.e("result", get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
};
所以Future
+ Callable
的組合可以更方便的獲取子線程任務(wù)的執(zhí)行結(jié)果套啤,更好的控制任務(wù)的執(zhí)行宽气,主要的用法先說(shuō)這么多了,其實(shí)AsyncTask
內(nèi)部也是類(lèi)似的實(shí)現(xiàn)潜沦!
注意萄涯,Future
并不能取消掉運(yùn)行中的任務(wù),這點(diǎn)在后邊的AsyncTask
解析中有提到唆鸡。
三涝影、線程池
Java 中線程池的具體的實(shí)現(xiàn)類(lèi)是ThreadPoolExecutor
,繼承了Executor
接口喇闸,這些線程池在 Android 中也是通用的袄琳。使用線程池的好處:
- 方便對(duì)線程進(jìn)行管理
- 線程復(fù)用,避免大量創(chuàng)建燃乍、銷(xiāo)毀線程帶來(lái)的性能開(kāi)銷(xiāo)
- 可控制線程的最大并發(fā)數(shù)唆樊,避免線程之間搶占資源造成阻塞
常用的構(gòu)造函數(shù)如下:
public ThreadPoolExecutor(
// 線程池的核心線程數(shù),如果設(shè)置allowCoreThreadTimeOut屬性為true刻蟹,當(dāng)閑置時(shí)間大于keepAliveTime會(huì)被終止掉逗旁,否則會(huì)一直存活不受keepAliveTime影響
int corePoolSize,
// 線程池能容納的最大線程數(shù),超過(guò)該數(shù)量的將會(huì)被阻塞
int maximumPoolSize,
// 線程閑置的超時(shí)時(shí)間
long keepAliveTime,
// 超時(shí)時(shí)間的單位
TimeUnit unit,
// 線程池的任務(wù)隊(duì)列舆瘪,保存通過(guò)execute()提交的Runnable片效,如果任務(wù)隊(duì)列已滿(mǎn),則后續(xù)任務(wù)不被執(zhí)行
BlockingQueue<Runnable> workQueue,
// 創(chuàng)建新的線程
ThreadFactory threadFactory) {
}
一個(gè)常規(guī)線程池可以按照如下方式來(lái)實(shí)現(xiàn):
public class ThreadPool {
// CPU核心數(shù)
private int CPU_COUNT = Runtime.getRuntime().availableProcessors();
// 可同時(shí)下載的任務(wù)數(shù)(核心線程數(shù))
private int CORE_POOL_SIZE = CPU_COUNT;
// 線程池容納的最大線程數(shù)
private int MAX_POOL_SIZE = 2 * CPU_COUNT + 1;
// 超時(shí)時(shí)間
private long KEEP_ALIVE = 10L;
private ThreadPoolExecutor THREAD_POOL_EXECUTOR;
private ThreadFactory sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger();
@Override
public Thread newThread(@NonNull Runnable runnable) {
return new Thread(runnable, "download_task#" + mCount.getAndIncrement());
}
};
private ThreadPool() {
}
public static ThreadPool getInstance() {
return SingletonHolder.instance;
}
private static class SingletonHolder {
private static final ThreadPool instance = new ThreadPool();
}
private ThreadPoolExecutor getThreadPoolExecutor() {
if (THREAD_POOL_EXECUTOR == null) {
THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(
CORE_POOL_SIZE,
MAX_POOL_SIZE,
KEEP_ALIVE,
TimeUnit.SECONDS,
new LinkedBlockingDeque<Runnable>(),
sThreadFactory);
}
return THREAD_POOL_EXECUTOR;
}
public void execute(Runnable command) {
getThreadPoolExecutor().execute(command);
}
}
執(zhí)行任務(wù):
ThreadPool.getInstance().execute(new Runnable() {
@Override
public void run() {
// do something
}
});
基于ThreadPoolExecutor
英古,系統(tǒng)擴(kuò)展了幾類(lèi)具有新特性的線程池:
// 創(chuàng)建一個(gè)線程數(shù)量固定的線程池淀衣,核心線程數(shù)就是線程池能容納的最大線程數(shù),同時(shí)線程將一直存活召调,除非線程池被關(guān)閉
// 如果任何線程在執(zhí)行期間因故障而終止膨桥,在關(guān)閉之前蛮浑,如果需要,新線程將取代它執(zhí)行后續(xù)任務(wù),
// 如果所有線程都處于活動(dòng)狀態(tài)只嚣,新來(lái)的任務(wù)需要等待沮稚,直到有空閑線程
ExecutorService fixedThreadPool = Executors.newFixedThreadPool();
// 該線程池只有非核心線程,數(shù)量為Integer.MAX_VALUE
// 按需創(chuàng)建線程册舞,沒(méi)有空閑線程時(shí)會(huì)創(chuàng)建新線程蕴掏,否則復(fù)用空閑線程,任何任務(wù)都會(huì)被立即執(zhí)行
// 超時(shí)時(shí)間為60秒调鲸,當(dāng)線程池長(zhǎng)時(shí)間閑置時(shí)線程都會(huì)被終止掉盛杰,幾乎不占用系統(tǒng)資源
// 任務(wù)隊(duì)列比較特殊是SynchronousQueue,而非一般的LinkedBlockingQueue
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
// 創(chuàng)建一個(gè)核心線程數(shù)固定的線程池藐石,可容納的最大線程數(shù)量為Integer.MAX_VALUE饶唤,非核心線程的超時(shí)時(shí)間為0
// 主要用于執(zhí)行定時(shí)任務(wù)和有固定周期的任務(wù)
ExecutorService scheduledThreadPool = Executors.newScheduledThreadPool();
// 該線程池中只有一個(gè)核心線程,所有任務(wù)都通過(guò)該線程執(zhí)行
// 任務(wù)之間不用考慮線程同步的問(wèn)題
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
// Android api level 24 新加的
// 會(huì)根據(jù)所需的并行層次來(lái)動(dòng)態(tài)創(chuàng)建和關(guān)閉線程贯钩,試圖減少任務(wù)隊(duì)列的大小,所以比較適于高負(fù)載的環(huán)境
// 也比較適用于當(dāng)執(zhí)行的任務(wù)會(huì)創(chuàng)建更多任務(wù)办素,如遞歸任務(wù)
ExecutorService workStealingPool = Executors.newWorkStealingPool();
線程池可以通過(guò)execute()
角雷、submit()
方法開(kāi)始執(zhí)行任務(wù),主要差別從方法的聲明就可以看出性穿,由于submit()
有返回值勺三,可以方便得到任務(wù)的執(zhí)行結(jié)果:
void execute(Runnable command)
Future<?> submit(Runnable task)
<T> Future<T> submit(Callable<T> task)
<T> Future<T> submit(Runnable task, T result)
要關(guān)閉線程池可以使用如下方法:
void shutdown()
List<Runnable> shutdownNow()
四、IntentService需曾、HandlerThread
1吗坚、基本使用
IntentService 是 Android 中一種特殊的 Service,可用于執(zhí)行后臺(tái)耗時(shí)任務(wù)呆万,任務(wù)結(jié)束時(shí)會(huì)自動(dòng)停止商源,由于屬于系統(tǒng)的四大組件之一,相比一般線程具有較高的優(yōu)先級(jí)谋减,不容易被殺死牡彻。用法和普通 Service 基本一致,只需要在onHandleIntent()
中處理耗時(shí)任務(wù)即可:
public class DomainService extends IntentService {
public DomainService() {
super("DomainService");
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
// 處理耗時(shí)任務(wù)
}
@Override
public void onDestroy() {
super.onDestroy();
}
}
至于 HandlerThread出爹,它是 IntentService 內(nèi)部實(shí)現(xiàn)的重要部分庄吼,細(xì)節(jié)內(nèi)容會(huì)在 IntentService 源碼中說(shuō)到。
2严就、源碼解析
IntentService 首次創(chuàng)建被啟動(dòng)的時(shí)候其生命周期方法onCreate()
會(huì)先被調(diào)用总寻,所以我們從這個(gè)方法開(kāi)始分析:
@Override
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
這里出現(xiàn)了 HandlerThread 和 ServiceHandler 兩個(gè)類(lèi),先搞明白它們的作用梢为,以便后續(xù)的分析渐行。
首先看 HandlerThread 的核心實(shí)現(xiàn):
public class HandlerThread extends Thread {
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
首先它繼承了 Thread 類(lèi)轰坊,可以當(dāng)做子線程來(lái)使用,并在 run()
方法中創(chuàng)建了一個(gè)消息循環(huán)系統(tǒng)殊轴、開(kāi)啟消息循環(huán)衰倦。
ServiceHandler 是 IntentService 的內(nèi)部類(lèi),繼承了 Handler旁理,具體內(nèi)容后續(xù)分析:
private final class ServiceHandler extends Handler {
}
現(xiàn)在回過(guò)頭來(lái)看 onCreate()
方法主要是一些初始化的操作樊零, 首先創(chuàng)建了一個(gè) thread
對(duì)象,并啟動(dòng)線程孽文,然后用其內(nèi)部的 Looper 對(duì)象 創(chuàng)建一個(gè) mServiceHandler
對(duì)象驻襟,將子線程的 Looper 和 ServiceHandler 建立了綁定關(guān)系,這樣就可以使用mServiceHandler
將消息發(fā)送到子線程去處理了芋哭。
生命周期方法 onStartCommand()
方法會(huì)在 IntentService 每次被啟動(dòng)時(shí)調(diào)用沉衣,一般會(huì)這里處理啟動(dòng) IntentService 傳遞 Intent 解析攜帶的數(shù)據(jù):
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
又調(diào)用了start()
方法:
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
就是用mServiceHandler
發(fā)送了一條包含startId
和intent
的消息,消息的發(fā)送還是在主線程進(jìn)行的减牺,接下來(lái)消息的接收豌习、處理就是在子線程進(jìn)行的:
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
當(dāng)接收到消息時(shí),通過(guò)onHandleIntent()
方法在子線程處理 intent 對(duì)象拔疚,onHandleIntent()
方法執(zhí)行結(jié)束后肥隆,通過(guò)stopSelf(msg.arg1)
等待所有消息處理完畢后終止服務(wù)。
為什么消息的處理是在子線程呢稚失?這里涉及到 Handler 的內(nèi)部消息機(jī)制栋艳,簡(jiǎn)單的說(shuō),因?yàn)?code>ServiceHandler使用的Looper
對(duì)象就是在HandlerThread
這個(gè)子線程類(lèi)里創(chuàng)建的句各,并通過(guò)Looper.loop()
開(kāi)啟消息循環(huán)吸占,不斷從消息隊(duì)列(單鏈表)中取出消息,并執(zhí)行凿宾,截取loop()
的部分源碼:
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
msg.target.dispatchMessage(msg);
}
dispatchMessage()
方法間接會(huì)調(diào)用handleMessage()
方法矾屯,所以最終onHandleIntent()
就在子線程中劃線執(zhí)行了,即HandlerThread
的run()
方法初厚。
這就是 IntentService 實(shí)現(xiàn)的核心问拘,通過(guò)HandlerThread
+ Hanlder
把啟動(dòng) IntentService 的 Intent 從主線程切換到子線程,實(shí)現(xiàn)讓 Service 可以處理耗時(shí)任務(wù)的功能惧所!
五骤坐、AsyncTask
1、基本使用
AsyncTask 是 Android 中輕量級(jí)的異步任務(wù)抽象類(lèi)下愈,它的內(nèi)部主要由線程池以及 Handler 實(shí)現(xiàn)纽绍,在線程池中執(zhí)行耗時(shí)任務(wù)并把結(jié)果通過(guò) Handler 機(jī)制中轉(zhuǎn)到主線程以實(shí)現(xiàn)UI操作。典型的用法如下:
/**
* 三個(gè)泛型參數(shù)Params势似、 Progress拌夏、 Result分別表示耗時(shí)任務(wù)輸入?yún)?shù)類(lèi)型僧著、進(jìn)度類(lèi)型、返回的結(jié)果類(lèi)型
*/
public class DownloadAsyncTask extends AsyncTask<String, Integer, String> {
/**
* 在主線程執(zhí)行障簿,可在耗時(shí)任務(wù)開(kāi)始前做一些準(zhǔn)備工作
*/
@Override
protected void onPreExecute() {
super.onPreExecute();
Log.e("onPreExecute", "download prepare");
}
/**
* 在線程池中執(zhí)行耗時(shí)任務(wù)
*
* @param urls 輸入?yún)?shù)
* @return 耗時(shí)任務(wù)的結(jié)果
*/
@Override
protected String doInBackground(String... urls) {
String url = "";
for (String temp : urls) {
// 執(zhí)行耗時(shí)任務(wù)
try {
for (int i = 0; i <= 100; i += 10) {
// publishProgress()用來(lái)更新任務(wù)進(jìn)度盹愚,會(huì)調(diào)用onProgressUpdate()方法
publishProgress(i);
Thread.sleep(20);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
url = temp;
}
return url;
}
/**
* 在主線程執(zhí)行,進(jìn)度更新時(shí)會(huì)被調(diào)用
*
* @param values values[0]代表進(jìn)度
*/
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
Log.e("onProgressUpdate", values[0] + "%");
}
/**
* 在主線程執(zhí)行站故,耗時(shí)任務(wù)執(zhí)行結(jié)束
*
* @param url doInBackground()的返回值
*/
@Override
protected void onPostExecute(String url) {
super.onPostExecute(url);
Log.e("onPostExecute", url + " download finish");
}
}
從 Android3.0 開(kāi)始皆怕,AsyncTask 默認(rèn)是串行執(zhí)行的:
new DownloadAsyncTask().execute("url-1");
new DownloadAsyncTask().execute("url-2");
如果需要并行執(zhí)行可以這么做:
new DownloadAsyncTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "url-1");
new DownloadAsyncTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "url-2");
2、源碼解析
AsyncTask 的源碼不多西篓,還是比較容易理解的愈腾。根據(jù)上邊的用法,可以從execute()
方法開(kāi)始我們的分析:
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
看到@MainThread
注解了嗎岂津?所以execute()
方法需要在主線程執(zhí)行哦虱黄!
進(jìn)而又調(diào)用了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;
}
可以看到,當(dāng)任務(wù)正在執(zhí)行或者已經(jīng)完成吮成,如果又被執(zhí)行會(huì)拋出異常橱乱!回調(diào)方法onPreExecute()
最先被執(zhí)行了。
傳入的sDefaultExecutor
參數(shù)粱甫,是一個(gè)自定義的串行線程池對(duì)象仅醇,所有任務(wù)在該線程池中排隊(duì)執(zhí)行:
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);
}
}
}
可以看到SerialExecutor
線程池僅用于任務(wù)的排隊(duì),THREAD_POOL_EXECUTOR
線程池才是用于執(zhí)行真正的任務(wù)魔种,就是我們線程池部分講到的ThreadPoolExecutor
:
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;
}
再回到executeOnExecutor()
方法中,那么exec.execute(mFuture)
就是觸發(fā)線程池開(kāi)始執(zhí)行任務(wù)的操作了粉洼。
那executeOnExecutor()
方法中的mWorker
是什么节预?mFuture
是什么?答案在 AsyncTask 的構(gòu)造函數(shù)中:
public AsyncTask(@Nullable Looper callbackLooper) {
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
postResult(result);
}
return result;
}
};
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 occurred while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
}
原來(lái)mWorker
是一個(gè)Callable
對(duì)象属韧,mFuture
是一個(gè)FutureTask
對(duì)象安拟,繼承了Runnable
接口。所以mWorker
的call()
方法會(huì)在mFuture
的run()
方法中執(zhí)行宵喂,所以mWorker
的call()
方法在線程池得到執(zhí)行糠赦!
同時(shí)doInBackground()
方法就在call()
中方法,所以我們自定義的耗時(shí)任務(wù)邏輯得到執(zhí)行锅棕,不就是我們第二部分講的那一套嗎拙泽!
doInBackground()
的返回值會(huì)傳遞給postResult()
方法:
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
就是通過(guò) Handler 將最終的耗時(shí)任務(wù)結(jié)果從子線程發(fā)送到主線程,具體的過(guò)程是這樣的裸燎,getHandler()
得到的就是 AsyncTask 構(gòu)造函數(shù)中初始化的mHandler
顾瞻,mHander
又是通過(guò)getMainHandler()
賦值的:
private static Handler getMainHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler(Looper.getMainLooper());
}
return sHandler;
}
}
可以在看到sHandler
是一個(gè)InternalHandler
類(lèi)對(duì)象:
private static class InternalHandler extends Handler {
public InternalHandler(Looper looper) {
super(looper);
}
@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;
}
}
}
所以getHandler()
就是在得到在主線程創(chuàng)建的InternalHandler
對(duì)象,所以
就可以完成耗時(shí)任務(wù)結(jié)果從子線程到主線程的切換德绿,進(jìn)而可以進(jìn)行相關(guān)UI操作了荷荤。
當(dāng)消息是MESSAGE_POST_RESULT
時(shí)退渗,代表任務(wù)執(zhí)行完成,finish()
方法被調(diào)用:
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
如果任務(wù)沒(méi)有被取消的話(huà)執(zhí)行onPostExecute()
蕴纳,否則執(zhí)行onCancelled()
会油。
如果消息是MESSAGE_POST_PROGRESS
,onProgressUpdate()
方法被執(zhí)行古毛,根據(jù)之前的用法可以onProgressUpdate()
的執(zhí)行需要我們手動(dòng)調(diào)用publishProgress()
方法翻翩,就是通過(guò) Handler 來(lái)發(fā)送進(jìn)度數(shù)據(jù):
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
進(jìn)行中的任務(wù)如何取消呢?AsyncTask 提供了一個(gè)cancel(boolean mayInterruptIfRunning)
喇潘,參數(shù)代表是否中斷正在執(zhí)行的線程任務(wù)体斩,但是呢并不靠譜,cancel()
的方法注釋中有這么一段:
Calling this method will result in {@link #onCancelled(Object)} being
invoked on the UI thread after {@link #doInBackground(Object[])}
returns. Calling this method guarantees that {@link #onPostExecute(Object)}
is never invoked. After invoking this method, you should check the
value returned by {@link #isCancelled()} periodically from
{@link #doInBackground(Object[])} to finish the task as early as
possible.
大致意思就是調(diào)用cancel()
方法后颖低,onCancelled(Object)
回調(diào)方法會(huì)在doInBackground()
之后被執(zhí)行而onPostExecute()
將不會(huì)被執(zhí)行絮吵,同時(shí)你應(yīng)該doInBackground()
回調(diào)方法中通過(guò)isCancelled()
來(lái)檢查任務(wù)是否已取消,進(jìn)而去終止任務(wù)的執(zhí)行忱屑!
所以只能自己動(dòng)手了:
@Override
protected String doInBackground(String... urls) {
.........
if (isCancelled()){
// 手動(dòng)拋出異常蹬敲,并自己捕獲或者直接return
}
.........
}
AsyncTask 整體的實(shí)現(xiàn)流程就這些了,源碼是最好的老師莺戒,自己跟著源碼走一遍有些問(wèn)題可能就豁然開(kāi)朗了伴嗡!