AysncTask
AsyncTask本質上是一個Handler和線程池的封裝,線程池用來異步處理後臺任務,handler用來發送消息進行UI方面的交互
優點:
- 適合簡單短時的異步任務,可以同時爆發數量較大的異步任務(支持線程池,任務隊列128個,最多同時併發5個)
- 過程可控(即onPreExecute、doInBackground、onPostExecute等)
AsyncTask
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
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;
}
這裏調用onPreExecute後開始觸發線程池 ,跑子線程。線程池中最終運行mFuture的run方法,run調用innerRun
void innerRun() {
if (!compareAndSetState(READY, RUNNING))
return;
runner = Thread.currentThread();
if (getState() == RUNNING) { // recheck after setting thread
V result;
try {
result = callable.call();
} catch (Throwable ex) {
setException(ex);
return;
}
set(result);
} else {
releaseShared(0); // cancel
}
}
這邊的callable.call其實就是調用WorkerRunnable.call
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
return postResult(doInBackground(mParams));
}
很明顯就是在線程內部調用了doInBackground,之後把doInBackground的結果作爲參數調用postResult;這裏先揭祕下,postResult會利用Handler回到主線程調用onPostExecute
private Result postResult(Result result) {
Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
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;
}
}
}
可以看到這邊有handleMessage有兩個分支一個分支finish最終調用onPostExecute,另一個onProgressUpdate是更新進度的
HandlerThread
HandlerThread本質上就是一個Thread和Looper的封裝。與AsyncTask的區別在於,AsyncTask適合短時併發數多的小任務,HandlerThread適合耗時多數據量大的任務。但HandlerThread同時只能執行一個任務,多個任務會以隊列的形式串行執行。
優點:
- 結構清晰,功能定義明確
- 對於多個後臺任務時,簡單,清晰
用法
HandlerThread mHandlerThread = new HandlerThread("MyHandlerThread");
mHandlerThread.start();
//HandlerThread內部的Looper,這邊的代碼會在HandlerThread裏的子線程中執行
Handler handler = new Handler(mHandlerThread.getLooper()){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//這裏可以執行異步任務,執行完可調用mMainHandler回到主線程刷新UI
}
};
//發送消息觸發HandlerThread的handler,執行異步任務
handler.sendEmptyMessage(1);
//這種用法與sendMessage差不多,只不過這邊的Message自帶裏處理Callback即Runnable的處理
handler.post(new Runnable() {
@Override
public void run() {
}
});
//主線程的Looper
Handler mMainHandler = new Handler(Looper.getMainLooper()){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//更新UI
}
};
//清空HandlerThread內部消息
mHandlerThread.quit();//清空所有消息
mHandlerThread.quitSafely();//只清空延遲消息
HandlerThread源碼
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
protected void onLooperPrepared() {
}
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll(); //喚醒其他線程的等待鎖,這邊是爲了喚醒getLooper()方法中的等待鎖
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// 線程開始,該方法會一直等待Looper對象創建完成纔會執行,
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
public int getThreadId() {
return mTid;
}
}
源碼很短,沒有太多難點主要是一些細節處理。
IntentService
IntentService本質上是一個Service和HandlerThread的封裝。
優點:
- IntentService創建獨立線程來處理Intent請求
- IntentService處理請求後會自動停止
注意點:IntentService只能使用bindService,如果用startService來啓動的話則onHandleIntent則不會被調用,失去IntenService的 意義,變得跟普通Service一樣。