AsyncTask源碼分析

AsyncTask簡介

  • AsyncTask,是android提供的輕量級的異步類,可以直接繼承AsyncTask,在類中實現異步操作,並提供接口反饋當前異步執行的程度(可以通過接口實現UI進度更新),最後反饋執行的結果給UI主線程。

  • AsyncTask實際上就是封裝了Thread和Handler,可以讓我們在後臺進行計算並且把計算的結果及時更新到UI上,而這些正是Thread+Handler所做的事情,AsyncTask的作用就是簡化Thread+Handler

  • 在1.6之前,AsyncTask是串行執行任務的,1.6的時候AsyncTask開始採用線程池裏處理並行任務,但是從3.0開始,爲了避免AsyncTask所帶來的併發錯誤,AsyncTask又採用一個線程來串行執行任務

AsyncTask步驟

一個異步任務的執行一般包括以下幾個步驟:

1.execute(Params… params):

執行一個異步任務,需要我們在代碼中調用此方法,觸發異步任務的執行。

2.onPreExecute():

在execute(Params…params)被調用後立即執行,一般用來在執行後臺任務前對UI做一些標記。在主線程中執行。

3.doInBackground(Params…params):

在onPreExecute()完成後立即執行,用於執行較爲費時的操作,此方法將接收輸入參數和返回計算結果。在執行過程中可以調用publishProgress(Progress…values)來更新進度信息。在線程池中執行。

4.onProgressUpdate(Progress…values):

在調用publishProgress(Progress…values)時,此方法被執行,直接將進度信息更新到UI組件上。 在主線程中執行。

5.onPostExecute(Result result):

當後臺操作結束時,此方法將會被調用,計算結果將做爲參數傳遞到此方法中,直接將結果顯示到UI組件上。在主線程中執行。

注意事項

1.異步任務的實例必須在UI線程中創建。
2.AsyncTask的類必須在UI線程加載(從4.1開始系統會幫我們自動完成)
3.execute(Params… params)方法必須在UI線程中調用。
4.不要在你的程序中去直接調用onPreExecute(), onPostExecute, doInBackground, onProgressUpdate方法
一個AsyncTask對象只能執行一次,即只能調用一次execute方法,否則會報運行時異常
5.不能在doInBackground(Params… params)中更改UI組件的信息。
6.一個AsyncTask對象只能執行一次,即只能調用一次execute方法,否則會報運行時異常
7.AsyncTask不是被設計爲處理耗時操作的,耗時上限爲幾秒鐘,如果要做長耗時操作,強烈建議你使用Executor,ThreadPoolExecutor以及FutureTask
8.在1.6之前,AsyncTask是串行執行任務的,1.6的時候AsyncTask開始採用線程池裏處理並行任務,但是從3.0開始,爲了避免AsyncTask所帶來的併發錯誤,AsyncTask又採用一個線程來串行執行任務

AsyncTask工作原理

AsyncTask啓動首先會調用execute,先從execute方法開始分析,execute又會調用executeOnExecutor,它們的實現如下:

  @MainThread
    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }

    @MainThread
    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;
    }

sDefaultExecutor實現了一個串行的線程池,一個進程中所有的AsyncTask都會在這個線程池中排隊。onPreExecute會先執行。然後通過exec.execute(mFuture)執行這個線程池。

/** 
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread. 
     */  
    public AsyncTask() {  
        mWorker = new WorkerRunnable<Params, Result>() {  
            public Result call() throws Exception {  
                mTaskInvoked.set(true);  

                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);  
                //noinspection unchecked  
                return postResult(doInBackground(mParams));  
            }  
        };  

        mFuture = new FutureTask<Result>(mWorker) {  
            @Override  
            protected void done() {  
                try {  
                    postResultIfNotInvoked(get());  
                } catch (InterruptedException e) {  
                    android.util.Log.w(LOG_TAG, e);  
                } catch (ExecutionException e) {  
                    throw new RuntimeException("An error occured while executing doInBackground()",  
                            e.getCause());  
                } catch (CancellationException e) {  
                    postResultIfNotInvoked(null);  
                }  
            }  
        };  
    }  

首先系統會把AsyncTask的mParams參數封裝爲FutureTask對象,FutureTask是一個併發類。接着這個FutureTask會交給SerialExecutor的execute方法去處理,execute首先會把FutureTask插入任務隊列mTasks,詳細實現如下:

/*串行執行器的實現,我們要好好看看,它是怎麼把並行轉爲串行的 
 *目前我們需要知道,asyncTask.execute(Params ...)實際上會調用 
 *SerialExecutor的execute方法,這一點後面再說明。也就是說:當你的asyncTask執行的時候, 
 *首先你的task會被加入到任務隊列,然後排隊,一個個執行 
 */  
private static class SerialExecutor implements Executor {  
    //線性雙向隊列,用來存儲所有的AsyncTask任務  
    final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();  
    //當前正在執行的AsyncTask任務  
    Runnable mActive;  

    public synchronized void execute(final Runnable r) {  
        //將新的AsyncTask任務加入到雙向隊列中  
        mTasks.offer(new Runnable() {  
            public void run() {  
                try {  
                    //執行AsyncTask任務  
                    r.run();  
                } finally {  
                    //當前AsyncTask任務執行完畢後,進行下一輪執行,如果還有未執行任務的話  
                    //這一點很明顯體現了AsyncTask是串行執行任務的,總是一個任務執行完畢纔會執行下一個任務  
                    scheduleNext();  
                }  
            }  
        });  
        //如果當前沒有任務在執行,直接進入執行邏輯  
        if (mActive == null) {  
            scheduleNext();  
        }  
    }  

    protected synchronized void scheduleNext() {  
        //從任務隊列中取出隊列頭部的任務,如果有就交給併發線程池去執行  
        if ((mActive = mTasks.poll()) != null) {  
            THREAD_POOL_EXECUTOR.execute(mActive);  
        }  
    }  
}  

SerialExecutor實現了AsyncTask的排隊過程。ArrayDeque 類提供了可調整大小的陣列,並實現了Deque接口。從任務隊列中取出隊列頭部的任務,如果有就交給併發線程池HREAD_POOL_EXECUTOR去執行。

THREAD_POOL_EXECUTOR線程池用於真正執行任務。

//獲取當前的cpu核心數  
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();  
//線程池核心容量  
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;  
//線程池最大容量  
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;  
//過剩的空閒線程的存活時間  
private static final int KEEP_ALIVE = 1;  
//ThreadFactory 線程工廠,通過工廠方法newThread來獲取新線程  
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());  
    }  
};  
//靜態阻塞式隊列,用來存放待執行的任務,初始容量:128個  
private static final BlockingQueue<Runnable> sPoolWorkQueue =  
        new LinkedBlockingQueue<Runnable>(128);  

/** 
 * 靜態併發線程池,可以用來並行執行任務,儘管從3.0開始,AsyncTask默認是串行執行任務 
 * 但是我們仍然能構造出並行的AsyncTask 
 */  
public static final Executor THREAD_POOL_EXECUTOR  
        = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,  
                TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);  

WorkerRunnable的call()方法最終會在線程池中執行,如下

    mWorker = new WorkerRunnable<Params, Result>() {  
            public Result call() throws Exception {  
                mTaskInvoked.set(true);  

                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);  
                //noinspection unchecked  
                return postResult(doInBackground(mParams));  
            }  
        };            

mTaskInvoked.set(true),表示當前任務已經被調用,然後執行doInBackground方法,接着返回值傳遞給postResult()方法,如下:

//doInBackground執行完畢,發送消息  
    private Result postResult(Result result) {  
        @SuppressWarnings("unchecked")  
        Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,  
                new AsyncTaskResult<Result>(this, result));  
        message.sendToTarget();  
        return result;  
    }  

postResult會通過sHandler發送一個MESSAGE_POST_RESULT的消息。sHandler實現如下:

//AsyncTask內部Handler,用來發送後臺計算進度更新消息和計算完成消息  
    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;  
            }  
        }  
    }  

sHandler收到MESSAGE_POST_RESULT後會調用finish方法,如果被取消任務,就調用onCancelled,否則調用onPostExecute:

//任務結束的時候會進行判斷,如果任務沒有被取消,則onPostExecute會被調用  
    private void finish(Result result) {  
        if (isCancelled()) {  
            onCancelled(result);  
        } else {  
            onPostExecute(result);  
        }  
        mStatus = Status.FINISHED;  
    }

解決3.0以上版本不能並行執行的問題

直接調用executeOnExecutor:
new MyAsyncTask(“AsyncTask#1”).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,”“);

發佈了46 篇原創文章 · 獲贊 23 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章