AsyncTask、HandlerThread、IntentSerivce原始碼解析
在進行耗時操作時,一般new Thread().start();開啟一個子執行緒,然後通過handler訊息去更新ui(關於handler可以看這裡:android Handler、Looper、Messsage、MessageQueue原始碼解析)或者利用AsyncTask進行耗時操作;
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //執行非同步任務 new WorkAsyncTask().execute(); } class WorkAsyncTask extends AsyncTask<Void,Void,Void>{ @Override protected void onPreExecute() { super.onPreExecute(); //任務開始的時候會回撥 ui執行緒 } @Override protected Void doInBackground(Void... params) { //操作任務邏輯 子執行緒 return null; } @Override protected void onProgressUpdate(Void... values) { super.onProgressUpdate(values); //更新進度的時候會回撥 ui執行緒 } @Override protected void onPostExecute(Void aVoid) { super.onPostExecute(aVoid); //操作完成更新ui回撥 ui執行緒 } } }
這是一段簡易的AsyncTask使用的程式碼,通過幾個方法的重寫和回撥就完成了非同步任務,表面上並沒有看到執行緒之間的切換,其實AsyncTask原始碼中利用handler訊息已經實現了執行緒之間的自由切換;先來看下AsyncTask的構造方法;
/** * Creates a new asynchronous task. This constructor must be invoked on the UI thread. *建立一個新的非同步任務,這個構造方法的例項化必須在ui執行緒中 */ public AsyncTask() { //例項化一個WorkerRunnable WorkerRunnable是一個抽閒類,implements Callable介面,所以在例項化的時候就必須重寫其中的call()方法 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 //呼叫doInBackground方法,進行非同步任務的操作,重寫其方法,進行具體邏輯,並返回結果 result = doInBackground(mParams); Binder.flushPendingCommands(); } catch (Throwable tr) { mCancelled.set(true); throw tr; } finally { //呼叫postResult方法,該方法中會利用handler訊息進行執行緒切換 postResult(result); } //將非同步任務的結果返回 return result; } }; //例項化一個FutureTask物件並將上面例項化好的WorkerRunnable作為引數傳入 //FutureTask<V> implements RunnableFuture<V>介面,可以重寫其中的run方法 mFuture = new FutureTask<Result>(mWorker) { @Override protected void done() { try { //會呼叫postResult方法,該方法中會利用handler訊息進行執行緒切換 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); } } }; }
上面就是AsyncTask的構造方法,在使用AsyncTask的時候例項化一個AsyncTask物件後呼叫execute();方法就會去執行該非同步任務;
@MainThread public final AsyncTask<Params, Progress, Result> execute(Params... params) { //根據指定的引數去執行一個非同步任務,並返回它自己,以保持對它的引用 //同時execute方法的執行要在ui執行緒中呼叫 return executeOnExecutor(sDefaultExecutor, params); }
@MainThread
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
if (mStatus != Status.PENDING) {
switch (mStatus) {
case RUNNING:
//不能執行非同步任務,當前非同步任務已經在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)");
}
}
//執行了executeOnExecutor方法後就會將mStatus表示改為Status.RUNNING狀態
mStatus = Status.RUNNING;
//會呼叫onPreExecute();方法,開始執行非同步任務的時候可以重寫做一些開始動作;
//onPreExecute方法是在ui執行緒中呼叫
onPreExecute();
mWorker.mParams = params;
//呼叫Executor中的execute去執行,並傳入一個FutureTask例項
exec.execute(mFuture);
return this;
}
通過上面這段程式碼可以知道:
不能對同一個非同步任務重複執行,一個非同步任務只能被執行一次;
onPreExecute方法是在ui執行緒中呼叫;
在呼叫executeOnExecutor()方法時需要傳入一個Executor物件,在例項化AsyncTask時就已經例項好一個全域性的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 volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
private static class SerialExecutor implements Executor {
//用於儲存Runnable的容器
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive;
public synchronized void execute(final Runnable r) {
//在Runnable容器的末尾插入一個Runnable
mTasks.offer(new Runnable() {
public void run() {
try {
//呼叫run方法
r.run();
} finally {
scheduleNext();
}
}
});
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
//呼叫Executor中的execute方法
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
Executor中execute方法的呼叫已經是在子執行緒中呼叫了;
/**
* An {@link Executor} that can be used to execute tasks in parallel.
*/
public static final Executor THREAD_POOL_EXECUTOR;
static {
//例項化一個執行緒池
//CORE_POOL_SIZE 池中保持執行緒的數量
//MAXIMUM_POOL_SIZE 池中允許的最大執行緒數
//KEEP_ALIVE_SECONDS 閒置回收時間,當執行緒數大於核心時,這是多餘空閒執行緒在終止之前等待新任務的最大時間。
//TimeUnit.SECONDS 時間單位
//sPoolWorkQueue 非同步任務佇列
//sThreadFactory 執行緒工廠
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系統設定執行緒池的一些引數;
//獲取cup數
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));
//池中允許的最大執行緒數 cup數*2+1
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
// 閒置回收時間
private static final int KEEP_ALIVE_SECONDS = 30;
//非同步任務佇列 128
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128);
//執行緒工廠
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());
}
};
如果當前執行緒池中的數量小於corePoolSize,建立並新增的任務。
如果當前執行緒池中的數量等於corePoolSize,緩衝佇列 workQueue未滿,那麼任務被放入緩衝佇列、等待任務排程執行。
如果當前執行緒池中的數量大於corePoolSize,緩衝佇列workQueue已滿,並且執行緒池中的數量小於maximumPoolSize,新提交任務會建立新執行緒執行任務。
如果當前執行緒池中的數量大於corePoolSize,緩衝佇列workQueue已滿,並且執行緒池中的數量等於maximumPoolSize,新提交任務由Handler處理。
當執行緒池中的執行緒大於corePoolSize時,多餘執行緒空閒時間超過keepAliveTime時,會關閉這部分執行緒。
執行完execute()方法,完成了執行緒的切換,這個時候在AsyncTask構造方法中例項化WorkerRunnable後會回撥其中的call()方法,在call方法中就會去呼叫doInBackground(mParams);方法,所以doInBackground(mParams);方法的執行是線上性程中執行,具體邏輯由子類去實現,將執行結果返回後就會去呼叫postResult(result);方法;
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
//通過getHandler獲取Handler例項,然後再獲取Message例項
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
//其實就是target.sendMessage(this); 也就是handler.sendMessage(message);
message.sendToTarget();
return result;
}
private static Handler getHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler();
}
return sHandler;
}
}
這個時候獲得到doInBackground(mParams);中執行的結果,通過handler實現了執行緒的切換,並將結果進行了傳送,通知ui去更新;
private static class InternalHandler extends Handler {
public InternalHandler() {
//在例項化handler時就已經例項化了一個mainLooper
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
//在ui執行緒中處理非同步任務的結果,更新ui
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
//在ui執行緒中更新非同步任務的進度
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
private void finish(Result result) {
if (isCancelled()) {
//如果非同步任務已經取消就會呼叫onCancelled()方法
onCancelled(result);
} else {
//呼叫onPostExecute方法更新ui,具體邏輯由子類實現
onPostExecute(result);
}
//修改非同步任務執行的狀態
mStatus = Status.FINISHED;
}
這樣一個非同步任務就執行完畢了,從中看出:
doInBackground(mParams);方法是在子執行緒中執行;
onPreExecute()、onProgressUpdate()、onPostExecute()、onCancelled()等方法都是在ui執行緒中執行;
AsyncTask就是handler+looper+執行緒池
AsyncTask在使用的時候並不需要去例項化handler和looper等物件,方便了不少,但是在使用的時候也需要注意:
執行緒池容量不夠丟擲異常;
記憶體洩露;
不過在使用的時候會發現AsyncTask這樣子使用一個執行緒,一個非同步任務,有時候並不能滿足需要,這個時候可以使用HandlerThread;
public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback {
private SurfaceView surfaceView;
private SurfaceHolder surfaceHolder;
private HandlerThread camareThread = new HandlerThread("camare_thread");
private Handler subHandler;
private Camera mCamera;
private byte[] buffers;
private Handler mainHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.d("jason4", Thread.currentThread().getName() + "_handleMessage");
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
surfaceView = (SurfaceView) findViewById(R.id.surface_view);
surfaceHolder = surfaceView.getHolder();
//設定監聽回撥
surfaceHolder.addCallback(this);
}
class CamareRunnable implements Runnable, Camera.PreviewCallback {
@Override
public void run() {
//開啟相機
//子執行緒中開啟
Log.d("jason1", Thread.currentThread().getName() + "_open");
mCamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);
try {
mCamera.setPreviewDisplay(surfaceHolder);
} catch (IOException e) {
e.printStackTrace();
}
Camera.Parameters parameters = mCamera.getParameters();
//設定相機引數
parameters.setPreviewSize(480, 320); //預覽畫面寬高
mCamera.setParameters(parameters);
//獲取預覽影象資料
buffers = new byte[480 * 320 * 4];
mCamera.addCallbackBuffer(buffers);
mCamera.setPreviewCallbackWithBuffer(this);
mCamera.startPreview();
Log.d("jason2", Thread.currentThread().getName() + "_run");
}
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
if (mCamera != null) {
mCamera.addCallbackBuffer(buffers);
//編碼
Log.d("jason3", Thread.currentThread().getName() + "_onPreviewFrame");
mainHandler.sendEmptyMessage(0);
}
}
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
//建立的時候回撥
//開啟HandlerThread
camareThread.start();
//例項化一個handler 將camareThread中的looper設定給subHandler
subHandler = new Handler(camareThread.getLooper());
subHandler.post(new CamareRunnable());
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
//改變的時候回撥
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
//銷燬的時候回撥
}
}
這是一段簡易的開啟相機和預覽的程式碼,執行發現jason1、jason2、jason3所列印的都是子執行緒,只有jason4列印的是主執行緒;這樣子就能一個執行緒多個任務了;那為什麼HandlerThread就可以呢?
/**
* Handy class for starting a new thread that has a looper. The looper can then be
* used to create handler classes. Note that start() must still be called.
*/
這個是HandlerThread的註釋,開啟一個執行緒已經擁有一個Looper,這個Looper可以用來建立一個Handler
所有可以將HandlerThread看作是Thread+Looper;確實HandlerThread 是繼承Thread的;
public class HandlerThread extends Thread
public HandlerThread(String name) {
super(name);
//name 是指定建立的HandlerThread例項的名稱
//執行緒的優先順序 一個預設的優先順序
//最終呼叫下面那個兩個引數的構造方法進行例項化
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
/**
* Constructs a HandlerThread.
* @param name
* @param priority The priority to run the thread at. The value supplied must be from
* {@link android.os.Process} and not from java.lang.Thread.
*/
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
例項化完畢後呼叫start()方法開啟一個執行緒;
@Override
public void run() {
//獲取當前執行緒id
mTid = Process.myTid();
//例項化一個Looper
Looper.prepare();
synchronized (this) {
//獲取例項化好的looper並賦值給mLooper
mLooper = Looper.myLooper();
notifyAll();
}
//設定執行緒的優先順序
Process.setThreadPriority(mPriority);
//這個方法可以根據自己的需要去重寫,如果想在Looper.loop();之前做一些事情,就可以重寫onLooperPrepared();
onLooperPrepared();
//開始輪詢
Looper.loop();
mTid = -1;
}
還提供了quit()、getLooper()等方法,其實HandlerThread的原始碼並不多;
接下來稍微說下IntentService
public class MyIntentService extends IntentService{
/**
* Creates an IntentService. Invoked by your subclass's constructor.
*
* @param name Used to name the worker thread, important only for debugging.
*/
public MyIntentService(String name) {
super(name);
}
@Override
protected void onHandleIntent(Intent intent) {
//onHandleIntent方法的回撥是在子執行緒中
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
}
}
IntentService extends Service就是一個Service,但是有不同於其他的Service,其實IntentService就是HandlerThread+Looper+Service;
/**
* Creates an IntentService. Invoked by your subclass's constructor.
*
* @param name Used to name the worker thread, important only for debugging.
*/
public IntentService(String name) {
super();
//和其他的Service不一樣,例項化需要傳入一個String型別的字串,該字串用於子執行緒中,不過僅用於debugging
mName = name;
}
開啟一個Service後,就會根據需要去重寫onCreate()、onStart()、onStartCommand()等方法;
@Override
public void onCreate() {
// TODO: It would be nice to have an option to hold a partial wakelock
// during processing, and to have a static startService(Context, Intent)
// method that would launch the service & hand off a wakelock.
super.onCreate();
//例項化一個HandlerThread
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
//開啟子執行緒
thread.start();
//獲取HandlerThread中例項化好的Looper
mServiceLooper = thread.getLooper();
//例項化一個Handler,並將HandlerThread中的Looper作為引數傳入,所以ServiceHandler所在的執行緒也是在子執行緒中
mServiceHandler = new ServiceHandler(mServiceLooper);
}
onStartCommand()方法話還是呼叫的是onStart()方法;
@Override
public void onStart(@Nullable Intent intent, int startId) {
//在onStart方法中主要就是通過handler傳送了一個訊息,不過該訊息的傳送是在子執行緒中傳送的
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
根據handler傳送的訊息會在ServiceHandler內部類中進行處理;
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
//訊息的處理也是在子執行緒中,所以onHandleIntent回撥是在子執行緒中
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
在onDestory的時候會將Looper移除掉;
@Override
public void onDestroy() {
mServiceLooper.quit();
}
其實IntentService的作用就是在開啟一個服務的時候,剛好如果有耗時操作時,不需要自己開啟一個執行緒或者非同步任務去執行該耗時操作,使用IntentService的onHandleIntent()方法中可以直接進行耗時操作。