1. 程式人生 > >AsyncTask、HandlerThread、IntentSerivce原始碼解析

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執行緒中執行;

onPreExecute()、onProgressUpdate()、onPostExecute()、onCancelled()等方法在ui執行緒中執行的原因是在例項化handler時例項化了一個main looper;

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()方法中可以直接進行耗時操作。