AsyncTask源碼分析

簡(jiǎn)介:AsyncTask是Android中用于異步操作的類。盡管現(xiàn)在已經(jīng)逐漸被強(qiáng)調(diào)舍棄,不過(guò)就源碼來(lái)說(shuō),AsyncTask還是一個(gè)挺不錯(cuò)的設(shè)計(jì)。鑒于上一篇文章非墨研究過(guò)線程池<a href="http://www.itdecent.cn/p/10da5cc92caa"> 線程池源碼分析</a>,正好以AsyncTask作為第二篇線程池相關(guān)的研究對(duì)象。

廢話不多說(shuō),我們先來(lái)看下,我們?cè)俅a中如何使用一個(gè)AsyncTask:

// demo1
new AsyncTask<String, Integer, String>() {

      protected void onProgressUpdate(Integer[] values) {
             //TODO  process update in UI Thread
      };
      
      protected void onPostExecute(String result) {
            //TODO on Execute finish
      };
      
   @Override
   protected String doInBackground(String... params) {
    int i = 0;
    while (i <= 100) {
     //todo something
     this.publishProgress(i);// notify progress change
     i ++;
    }
    return "result";
   }
  }.execute("params1","params2");

demo1是比較常見(jiàn)的做法,生成了一個(gè)AsyncTask對(duì)象,然后通過(guò)執(zhí)行execute方法。我們可以從demo1得到下面的結(jié)論:
1.execute方法里面需要傳入不定個(gè)數(shù)的參數(shù),參數(shù)的類型由AsyncTask的第二個(gè)泛型參數(shù)指定。如果你想指定多種類型的參數(shù),可以將你的類型做頂層抽象,或者是將多種參數(shù)封裝到一個(gè)新的類型里面,然后從這個(gè)類里面取。
2.在AsyncTask里面,一般以“on”打頭的方法都是在UI線程中執(zhí)行(其實(shí)并不準(zhǔn)確,實(shí)際上如果你的線程中存有Looper都可以使用)。
其實(shí)不管是在Android或者java,跟線程池或者線程相關(guān)的執(zhí)行動(dòng)作,常常都被命名成為execute。我們姑且有個(gè)印象,AsyncTask里面或許用到了線程池。我們來(lái)看下AsyncTask的具體源碼:

//code2
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;

    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());
        }
    };

    private static final BlockingQueue<Runnable> sPoolWorkQueue =
            new LinkedBlockingQueue<Runnable>(128);

    /**
     * An {@link Executor} that can be used to execute tasks in parallel.
     */
    public static final Executor THREAD_POOL_EXECUTOR
            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

正如code2代碼所示,我們上面方法名的假設(shè)并沒(méi)有錯(cuò),AsyncTask用了線程池,并且核心線程數(shù)量按照cpu的數(shù)量+1給出,最大線程數(shù)量按照2倍的cpu數(shù)量+1給出。至于為什么按照這個(gè)給值,非墨不得而知,這種數(shù)值或許是最優(yōu)解,但是為什么是最優(yōu)解呢?如果非墨得到了答案,非墨會(huì)在后續(xù)的文章中說(shuō)明。在這里,線程池被定義為常量,我們可以斷言,所有的AsyncTask都是共享線程池的。

//code3
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
//線性執(zhí)行隊(duì)列
    private static final int MESSAGE_POST_RESULT = 0x1;//post結(jié)果消息
    private static final int MESSAGE_POST_PROGRESS = 0x2;//進(jìn)度消息

    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
    private final WorkerRunnable<Params, Result> mWorker;//執(zhí)行對(duì)象
    private final FutureTask<Result> mFuture;//worker的一個(gè)裝飾對(duì)象,用于線程池操作

    private volatile Status mStatus = Status.PENDING;
    
    private final AtomicBoolean mCancelled = new AtomicBoolean();
    private final AtomicBoolean mTaskInvoked = new AtomicBoolean();

code3代碼里,定義了一個(gè)線性的執(zhí)行隊(duì)列,還有返回消息函數(shù),已經(jīng)一個(gè)工作對(duì)象worker,以及其包裝對(duì)象Future。用Status枚舉類型來(lái)記錄AsyncTask的狀態(tài)。用兩個(gè)原子變量mCancelledmTaskInvoked來(lái)標(biāo)記攔截一些操作。

//code3
public AsyncTask() {
        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);
                //noinspection unchecked
                return postResult(doInBackground(mParams));
            }
        };

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

在AsyncTask的構(gòu)造器里,生成了他的工作Worker對(duì)象和和Future對(duì)象。mWorker是一個(gè)WorkerRunnable類,它實(shí)現(xiàn)了java.util.concurrent.Callable接口。這點(diǎn)在非墨上篇的線程池分析中并沒(méi)有提及,但是萬(wàn)變不離其總,Callable接口對(duì)象最終一樣會(huì)包裝成為一個(gè)Runnable對(duì)象。而這種包裝的方式,需要一個(gè)叫做FutureTask的類來(lái)完成。這就是我們的mFuture對(duì)象。我們不妨回到我們的線程池相關(guān)代碼:

// code AbstractExecutorService.java
public <T> Future<T> submit(Callable<T> task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task);
        execute(ftask);
        return ftask;
    }
...
public interface RunnableFuture<V> extends Runnable, Future<V> {
    /**
     * Sets this Future to the result of its computation
     * unless it has been cancelled.
     */
    void run();
}

線程池使用Callable接口需要調(diào)用submit方法,在submit的代碼中,會(huì)將你的Callable對(duì)象包裝成為一個(gè)RunnableFuture對(duì)象。而RunnableFuture就實(shí)現(xiàn)了我們上篇所說(shuō)的Runnable接口。FutureTask是這個(gè)接口的真正實(shí)現(xiàn)類。這個(gè)類的主要工作是為run方法做裝飾。

// code FutureTask.java 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 {
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if (ran)
                    set(result);
            }
        } finally {
            ....
        }
    }

從代碼上看,FutureTask在實(shí)現(xiàn)的時(shí)候,使用了CAS算法來(lái)保證原子性。實(shí)現(xiàn)方式是使用了UnSafe類。注入了當(dāng)前的運(yùn)行線程。之后調(diào)用Callable的call方法來(lái)獲取返回值。然后通過(guò)set方法來(lái)設(shè)置你的result。

protected void set(V v) {
        if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {
            outcome = v;
            U.putOrderedInt(this, STATE, NORMAL); // final state
            finishCompletion();
        }
}

public V get() throws InterruptedException, ExecutionException {
        int s = state;
        if (s <= COMPLETING)
            s = awaitDone(false, 0L);
        return report(s);
    }

在FutureTask通過(guò)調(diào)用set來(lái)設(shè)置返回值了以后,另外一個(gè)線程通過(guò)調(diào)用get方法來(lái)獲取執(zhí)行結(jié)果。get方法在awaitDone的時(shí)候?qū)?zhí)行CAS操作阻塞。那么我們基于以上的理解,回到我們剛才的code3 AsyncTask 的構(gòu)造器代碼。
mFuture復(fù)寫了FutureTask的done方法,主要是為了處理當(dāng)你的AsyncTask沒(méi)有執(zhí)行的時(shí)候,默認(rèn)的返回值。我們構(gòu)造完AsyncTask了以后,接下去就要執(zhí)行它的execute方法。而execute方法內(nèi)部會(huì)調(diào)用到executeOnExecutor()方法。
-executeOnExecutor包含兩個(gè)種類型的參數(shù),這一種是Executor 變量,一般情況下指的是我們上面說(shuō)的線性執(zhí)行隊(duì)列SERIAL_EXECUTOR,第二種類型就是你傳入的參數(shù)列表。

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();//執(zhí)行前回調(diào)

        mWorker.mParams = params;
        exec.execute(mFuture);

        return this;
    }

在AsyncTask執(zhí)行executeOnExecutor將回調(diào)onPreExecute方法,然后將參數(shù)列表注入到mWorker對(duì)象中。onPreExecute 是個(gè)空的protected方法。因此,這個(gè)回調(diào)是在當(dāng)前調(diào)用線程中執(zhí)行的。
當(dāng)SERIAL_EXECUTOR.execute的時(shí)候,mFuture對(duì)象將會(huì)拋給共享線程池的execute 方法:

if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
 }

當(dāng)mFuture處理完結(jié)果以后,將通過(guò)postResult方法將結(jié)果拋給Handler所在的線程。實(shí)際上在Handler里面定義了兩個(gè)消息

1.private static final int MESSAGE_POST_RESULT = 0x1;
2. private static final int MESSAGE_POST_PROGRESS = 0x2;

分別用于返回結(jié)果到Handler所在線程,已經(jīng)發(fā)布進(jìn)度。發(fā)布進(jìn)度的消息可以調(diào)用publicProgress發(fā)送出去。我們來(lái)看下Result消息的處理:

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;
            }
        }
...
private void finish(Result result) {
        if (isCancelled()) {
            onCancelled(result);
        } else {
            onPostExecute(result);
        }
        mStatus = Status.FINISHED;
    }

消息處理將調(diào)用AsyncTask.finish方法。這個(gè)方法里面,將根據(jù)當(dāng)前task的狀態(tài)回調(diào)onCancelled方法,或者onPostExecute方法。這就是我們熟知的東西。要記住,這里面的回調(diào)方法,是在Handler所在的線程,一般是Ui線程中執(zhí)行。那么這個(gè)Handler所在的線程是不是在Ui線程呢?

private static final InternalHandler sHandler = new InternalHandler();

AsyncTask使用一個(gè)靜態(tài)成員變量來(lái)標(biāo)記使用的Handler,那么這個(gè)Handler所在的線程就是第一次加載該類的那個(gè)線程。那么第一次加載該類是在什么地方呢?我們知道,所有的Android進(jìn)程都是運(yùn)行在Davik的虛擬機(jī)上的,這個(gè)虛擬機(jī)的入口是ActivityThread類。這個(gè)類運(yùn)行的線程就是我們熟悉的UI線程。

//code ActivityThread.main
...
AsyncTask.init();
...

我們看到,在這個(gè)進(jìn)程剛開(kāi)始啟動(dòng),還沒(méi)進(jìn)入消息循環(huán)的時(shí)候,主進(jìn)程堆棧里,已經(jīng)對(duì)AsyncTask進(jìn)行了初始化的操作,這里面調(diào)用了AsyncTask的init方法:

/** @hide Used to force static handler to be created. */
    public static void init() {
        sHandler.getLooper();
    }

當(dāng)然這種調(diào)用沒(méi)有任何的實(shí)際的邏輯意義,就像注釋說(shuō)的,只是為了讓Handler生成而已。這樣,實(shí)際上我們對(duì)AsyncTask本身已經(jīng)分析的差不多了,最后一個(gè)小問(wèn)題就是:既然AsyncTask里面用到Future的模式,那AsyncTask是否Future的特性的。這是當(dāng)然的,AsyncTask里面提供了get接口,里面調(diào)用了Future的get接口,相當(dāng)于有了Future的特性:

public final Result get() throws InterruptedException, ExecutionException {
        return mFuture.get();
    }

好的,更多的功能,更多的特性就讓各位看官自己發(fā)掘吧。
——非墨

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容