不忘初心 砥礪前行, Tomorrow Is Another Day !html
本文概要:編程
在閱讀本文以前,須要對Handler消息機制有所瞭解才能深刻理解,若是對Handler瞭解還不夠深刻,能夠先閱讀這篇文章-Android消息機制Handlerbash
Android提供的一個異步類,它封裝了handler和線程池,從而簡化了更新UI的問題.多線程
AsyncTask是一個抽象的泛型類提供三個泛型參數分別爲 Params , Progress, Result.併發
public abstract class AsyncTask<Params, Progress, Result>
複製代碼
提供了4個核心方法:異步
onPreExecute :主線程中執行,任務開始前.ide
Result doInBackground(Params... params) : 子線程執行,執行任務時.oop
onProgressUpdate(Progress... values) : 主線程中執行,任務的執行進度更新時.post
onPostExecute(Result result) :主線程中執行,任務執行完畢時.學習
使用示例
public class AsyncTaskActivity extends AppCompatActivity implements View.OnClickListener {
//...省略部分代碼
class MyAsyncTask extends AsyncTask<String, Integer, Robot> {
@Override
protected void onPreExecute() {
mProgressDialog = new ProgressDialog(AsyncTaskActivity.this);
mProgressDialog.setMessage("正在加載");
mProgressDialog.setMax(10);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mProgressDialog.show();
}
@Override
protected Robot doInBackground(String... strings) {
Robot robot = null;
if (strings != null && strings.length > 0) {
for (int i = 0; i < 11; i++) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
publishProgress(i);
if (isCancelled()) {
break;
} else if (i == 10) {{
robot = new Robot("i", strings[0]);
}
}
} else {
throw new IllegalArgumentException("please set the params");
}
return robot;
}
@Override
protected void onProgressUpdate(Integer... values) {
if (values != null && values.length > 0) {
mProgressDialog.setProgress(values[0]);
}
}
@Override
protected void onPostExecute(Robot robot) {
mProgressDialog.dismiss();
tvName.setText(robot == null ? "參數不詳" : robot.getName());
}
@Override
protected void onCancelled() {
tvName.setText("任務被取消");
}
}
}
複製代碼
首先在onPreExecute初始化了ProgressDialog控件,接着經過doInBackground模擬執行耗時的機器人構造流程.在構造流程中調用了publishProgress去更新執行任務的進度.最後當任務執行完後在onPostExecute更新了機器人名,這時若是點擊了取消任務,那麼onCancelled則會調用.
關於AsyncTask的使用比較簡單就到這裏點到爲止.咱們具體來看它實現的原理.
源碼版本基於Android 8.0
對應源碼
public AsyncTask() {
this((Looper) null);
}
public AsyncTask(@Nullable Looper callbackLooper) {
//1.初始化Handler
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
//2.初始化WorkerRunnable,實際是一個實現Callable接口的類.
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
//...省略具體實現代碼,後面再分析.
return result;
}
};
//3.初始化FutureTask封裝了WorkerRunnable.
//在run方法中調用了mWorker的Call方法.
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
//...省略具體實現代碼,後面再分析.
}
};
}
複製代碼
這裏主要乾了三個初始化工做.
對應源碼
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();//執行onPreExecute
mWorker.mParams = params;//將輸入參數封裝到WorkRunnable
exec.execute(mFuture);//執行任務.
return this;
}
複製代碼
在excute方法中調用了executeOnExecutor方法,對這個流程作個小結.
在executeOnExecutor(sDefaultExecutor, params)方法中用到了sDefaultExecutor線程池.咱們接着看線程池的實現.
對應源碼
/**
* 用於任務的排隊的線程池
*/
private static class SerialExecutor implements Executor {
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive;
public synchronized void execute(final Runnable r) {
//1. 插入到任務隊列
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();//調用futureTask的run方法
} finally {//任務執行完畢,繼續執行下一個任務.
scheduleNext();
}
}
});
if (mActive == null) {//無任務,執行下一個.
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {//不斷從隊列中取任務
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
/**
* 執行任務的線程池THREAD_POOL_EXECUTOR
*/
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 BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128);
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;
}
複製代碼
這裏涉及到兩個線程池,也是AsyncTask的核心之處.
正由於SerialExecutor的存在,從上面能夠看出3.0以後是串行執行,因此不會有併發問題(執行飽和策略).
在futureTask的run方法會回調WorkerRunnable的call方法.這裏再回顧一下上一篇FutureTask的run方法源碼.
對應源碼
public void run() {
if (state != NEW ||
!U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
//回調callable的Call方法,獲取異步任務返回值.
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
set(result);
}
} finally {
//...省略部分代碼
}
}
複製代碼
這裏繼續回到最開始初始化WorkerRunnable時代碼.
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
/**
* 1.回調doInBackground方法
*/
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
postResult(result);
}
return result;
}
};
/**
* 2.經過handler將result傳遞出去
*/
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
/**
* 3. 處理消息
*/
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
//調用finish
result.mTask.finish(result.mData[0]);
break;
//...省略部分代碼
}
}
}
private void finish(Result result) {
if (isCancelled()) {
//回調已取消
onCancelled(result);
} else {
//回調onPostExecute
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
複製代碼
Call方法流程小結.
最後給出一張簡略版的AsyncTask的工做流程圖
到這裏AsyncTask的實現原理基本分析完成了,至於以前提到的3.0以前是並行的,3.0以後是串行的,若是想要實現並行能夠採用以下方式.
//方式一
executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,params);
//方式二
executeOnExecutor(自定義的線程池,params);
複製代碼
對於3.0如下是並行的效果,瞭解便可.這裏就不演示了.由於如今APP基本上5.0如下都不適配了,咱們又何須螳臂當車,節約寶貴的時間看將來趨勢的知識.
是一個消息循環的線程,這樣就能夠在該線程中使用Handler了.
對應源碼
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();//建立消息隊列
synchronized (this) {
mLooper = Looper.myLooper();
//Looper初始化完成,喚醒所以條件阻塞的線程
notifyAll();
}
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;
}
複製代碼
與普通線程相比,它的特色.
對應源碼
是一個Service,封裝了handlerThread與Handler.
正由於它是一個Service,因此不會容易被系統殺死.具備如下特色.
特色:
public class MyIntentService extends IntentService {
private static final String TAG = "MyIntentService";
public MyIntentService() {
super(TAG);
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
String taskName = intent.getStringExtra("taskName");
Log.d(TAG, "taskName: " + taskName);
SystemClock.sleep(2500);
if ("org.jason.taskOne".equals(taskName)){
Log.d(TAG, "do task: "+taskName);
}
}
@Override
public void onDestroy() {
Log.d(TAG, "onDestroy: ");
super.onDestroy();
}
}
private void doIntentService() {
//連續開三個服務測試
Intent intent = new Intent(this, MyIntentService.class);
intent.putExtra("taskName", "org.jason.taskOne");
startService(intent);
intent.putExtra("taskName", "org.jason.taskTw0");
startService(intent);
intent.putExtra("taskName", "org.jason.taskThree");
startService(intent);
}
//調用輸出
12-27 14:34:01.338 D/MyIntentService: taskName: org.jason.taskOne
12-27 14:34:03.839 D/MyIntentService: do task: org.jason.taskOne
12-27 14:34:03.840 D/MyIntentService: taskName: org.jason.taskTw0
12-27 14:34:06.341 D/MyIntentService: taskName: org.jason.taskThree
12-27 14:34:08.841 D/MyIntentService: onDestroy:
複製代碼
從上面日誌除了能夠看出它的特色外,還能發現任務都是按順序依次執行的.這與它內部的hanlder處理消息有關,由於handler的looper就是按順序處理消息的,接着咱們去看是如何實現的.
IntentService是一個繼承Service的抽象類.既然是Service咱們就按照Service的生命週期來分析.
對應源碼
public abstract class IntentService extends Service {
@Override
public void onCreate() {
super.onCreate();
//1.初始化一個HandlerThread
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
//2.初始化一個Handler,綁定HandlerThread的Looper.這樣就能使用handler,給HandlerThread線程發消息了.
//(也就是說綁定了在哪一個線程的looper,那麼發送的消息就在哪一個線程處理)
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
}
複製代碼
onStartCommand裏面調用了onStart方法,這裏直接看此方法.
對應源碼
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
//1.利用handler發送消息,消息內容就是咱們傳入的intent以及服務id標識.
mServiceHandler.sendMessage(msg);
}
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
//2.處理消息,
//注意:此handler綁定了HandlerThread的looper,因此是在子線程處理消息.
@Override
public void handleMessage(Message msg) {
//a.回調onHandleIntent
onHandleIntent((Intent)msg.obj);
//b.中止服務
stopSelf(msg.arg1);
}
}
複製代碼
@Override
public void onDestroy() {
//最後退出looper,這樣消息隊列才能退出,最終線程纔會銷燬.否則一直處於阻塞等待狀態.
mServiceLooper.quit();
}
複製代碼
前面講解HandlerThread時也有提過,當不使用時,需調用quit或者quitSafely來終止線程的執行.能夠看出系統源碼也是有這一步,因此當咱們自定義一個具備消息循環的線程必定記得退出,這是良好的編程習慣.
關於HandlerThread以及它的應用IntentService就介紹到這裏了.
因爲本人技術有限,若有錯誤的地方,麻煩你們給我提出來,本人不勝感激,你們一塊兒學習進步.
參考連接: