1. 程式人生 > >深入理解AsyncTask

深入理解AsyncTask

需要 cancel ngs trac 下載 深入理解 回收 生命 str

眾所周知,在Android中如果要執行耗時的操作,一般是在子線程中處理,使用new Thread的方法實現是最常見的方法之一。今天,我們要講的是另外一個,Android提供的異步任務類AsyncTask,底層是使用線程池實現的。

一、Android的線程

線程是操作系統的最小執行單位,它的創建和銷毀都會消耗一定的系統資源,如果頻繁的創建和銷毀,顯然不是高效的做法,正確的做法是,采用線程池,緩存一定量的線程,通過復用這些線程,避免造成極大的系統開銷。

二、AsyncTask

這是一個抽象類,使用方便,代碼簡潔,所以說是一個輕量級的異步類。它可以在線程池中執行後臺任務,然後把執行的進度和結果通過Handler傳給UI線程進而刷新視圖。

該類的聲明如下:

public abstract class AsyncTask<Params, Progress, Result>

其中各個參數的含義如下:

Params:開始異步任務執行時傳入的參數類型;

Progress:異步任務執行過程中,返回下載進度值的類型;

Result:異步任務執行完成後,返回的結果類型;

如果AsyncTask確定不需要傳遞具體參數,那麽這三個泛型參數可以用Void來代替。

三、AsyncTask源碼

AsyncTask內部封裝了2個線程池:SerialExecutor和THREAD_POOL_EXECUTOR,和1個Handler(IntentHandler)。其中SerialExecutor線程池用於任務的排隊,讓需要執行的多個耗時任務,按順序排列,THREAD_POOL_EXECUTOR線程池才真正地執行任務,InternalHandler用於從工作線程切換到主線程。部分源碼如下:

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);
            }
        }
    }
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
                sPoolWorkQueue, sThreadFactory);
        threadPoolExecutor.allowCoreThreadTimeOut(true);
        THREAD_POOL_EXECUTOR = threadPoolExecutor;
private static class InternalHandler extends Handler {
        public InternalHandler() {
            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
                    result.mTask.finish(result.mData[0]);
                    break;
                case MESSAGE_POST_PROGRESS:
                    result.mTask.onProgressUpdate(result.mData);
                    break;
            }
        }
    }

四、註意事項

1、因為執行後的結果要傳遞到主線程,所以使用Handler進行工作線程和主線程的切換,所以AsyncTask創建實例和execute需要在主線程調用;

2、onPreExecute(),onProgressUpdate(Progress... values),onPostExecute(Result result),onCancelled()方法是在主線程執行的,而doInBackground(Params... params)是在工作線程執行;

3、執行順序:onPreExecute() --> doInBackground() --> publishProgress() --> onProgressUpdate() --> onPostExecute(),如果不需要執行更新進度則為onPreExecute() --> doInBackground() --> onPostExecute(),其中publishProgress方法在doInBackground方法中調用,會觸發onProgressUpdate方法;

4、AsyncTask還提供了onCancelled()方法,它同樣在主線程中執行,當異步任務取消時,onCancelled()會被調用,這個時候onPostExecute()則不會被調用,但是要註意的是,AsyncTask中的cancel()方法並不是真正去取消任務,只是設置這個任務為取消狀態,我們需要在doInBackground()判斷終止任務。就好比想要終止一個線程,調用interrupt()方法,只是進行標記為中斷,需要在線程內部進行標記判斷然後中斷線程。

5、一個任務實例只能執行一次,如果執行第二次將會拋出異常。

五、AsyncTask使用不當的後果

1、生命周期:AsyncTask不與任何組件綁定生命周期,所以在Activity或者Fragment中創建執行AsyncTask時,最好在Activity或Fragment的onDestory()調用 cancel(boolean);

2、內存泄漏:如果AsyncTask被聲明為Activity的非靜態的內部類,那麽AsyncTask會保留一個對創建了AsyncTask的Activity的引用。如果Activity已經被銷毀,AsyncTask的後臺線程還在執行,它將繼續在內存裏保留這個引用,導致Activity無法被回收,引起內存泄露;

3、 結果丟失:屏幕旋轉或Activity在後臺被系統殺掉等情況會導致Activity的重新創建,之前運行的AsyncTask(非靜態的內部類)會持有一個之前Activity的引用,這個引用已經無效,這時調用onPostExecute()再去更新界面將不再生效。

參考鏈接:

http://www.jianshu.com/p/817a34a5f200

深入理解AsyncTask