AsyncTask源碼詳解

在分析源碼以前,首先引用一段源碼中的註釋說明AsyncTask的定義:java

AsyncTask可以正確,方便的使用UI線程。AsyncTask能夠在不用使用Threads 和 handlers的狀況下,操做後臺線程而且將結果發送給UI線程。 AsyncTask是爲Thread和Handler而設計的幫助類,而且它應當使用在一些耗時較短的操做上,若是須要讓線程保持長時間的運行,強烈的推薦使用 java.util.concurrent包中的如Excutor、ThreadPoolExecutor、FutureTask。android

在分析源碼以前,先看一段簡單的使用例子,方便理解:ide

private class DownloadFilesTask extends AsyncTask(URL, Integer, Long) {
      protected Long doInBackground(URL... urls) {
          int count = urls.length;
          long totalSize = 0;
          for (int i = 0; i < count; i++) {
              totalSize += Downloader.downloadFile(urls[i]);
              //將進度返回給主線程,用於更新進度。
              publishProgress((int) ((i / (float) count) * 100));
              // Escape early if cancel() is called
              if (isCancelled()) break;
          }
          return totalSize;
      }
 
      protected void onProgressUpdate(Integer... progress) {
          setProgressPercent(progress[0]);
      }
 
      protected void onPostExecute(Long result) {
          showDialog("Downloaded " + result + " bytes");
      }
 }
    
    //調用
    new DownloadFilesTask(url, 0, 1L).execute();
複製代碼

經過上面的例子咱們能夠看出AsyncTask的基本用法:就是用一個類繼承AsyncTask,而後分別實現三個方法: doInBackground()onProgressUpdate()onPostExecute()。使用的時候,只須要調用execute()方法便可。那麼下面咱們來看一下AsyncTask的源碼是怎麼實現的:oop

public abstract class AsyncTask<Params, Progress, Result> 複製代碼

AsyncTask是一個抽象類,而且包含了三個泛型參數,它們的含義咱們從名字應該能看得出來分別表示後臺任務的參數、進度、以及結果。 分別對應上面例子中的URL、Integer、Long。post

接下來咱們進入它的執行方法execute():this

public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
 }
複製代碼

能夠看到,execute()調用了execureOnExecutor()這個方法 (關於execute()有一點須要說明的是,AsyncTask最初是使用串行的方式處理多任務,可是從Android 1.6開始,將其改成並行的,可是爲了不併行帶來的錯誤,自從Android 3.2 以後又改回了串行模式 ) ,那麼下面看看execureOnExecutor()的源代碼:url

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;
}
複製代碼

從上面代碼中能夠看出,首先會判斷當前AsyncTask的狀態是否爲等待狀態,若是不是則報錯,是等待狀態將會執行onPreExecute(),也就是咱們自定義的進行後臺任務前的方法。而後會調用exec的execute()方法,那麼這個exec是什麼呢? 從execute()方法的參數能夠看出,exec是一個叫作sDefaultExecutor的變量,那麼咱們去看看這個變量是什麼:spa

public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
複製代碼

原來是SerialExecutor這個類的一個對象,再繼續看看SerialExecutor這個類的定義:線程

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);
        }
    }
}
複製代碼

能夠看出,在SerialExecutor內部,實現了一個task任務的隊列(ArrayDeque),而且從這裏的處理,咱們也能看出來以前在execute()方法解釋的時候說任務是串行的原理了(註釋有說明),而實現任務的串行執行的正是THREAD_POOL_EXECUTOR,從名字就能夠看出來是一個線程池的定義,咱們先來看看對於這個線程池的定義:設計

//線程池核心線程數 
    private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
	//線程池最大線程數
    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
		//非核心線程存活時間
    private static final int KEEP_ALIVE_SECONDS = 30;
		//線程工廠類
    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);

    /** * An {@link Executor} that can be used to execute tasks in parallel. */
    public static final Executor THREAD_POOL_EXECUTOR;

    static {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
                sPoolWorkQueue, sThreadFactory);
        threadPoolExecutor.allowCoreThreadTimeOut(true);
        THREAD_POOL_EXECUTOR = threadPoolExecutor;
    }
複製代碼

從上面的註釋咱們能夠看出,對於線程池的大小定義是和當前設備的CPU有關的,而核心線程數最大也不會超過4。那麼當若是線程數超過了最大線程數,其餘的只能阻塞排隊等待,那也就是說當有多個線程的時候不適合使用AsyncTask。

咱們再回到SerialExecutor類中,能夠看到在添加任務進隊列隊尾的時候,調用了r.run()這個方法,那麼咱們就須要知道這個r表明什麼,回看方法調用流程,咱們發如今executeOnExecutor()方法中,調用exec.execute()傳入了一個mFuture參數,那麼來看一下mFuture的定義:

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 occurred while executing doInBackground()",
                            e.getCause());
                } catch (CancellationException e) {
                    postResultIfNotInvoked(null);
                }
            }
        };
複製代碼

能夠看出,mFuture是一個FutureTask的對象,首先來看一下FutureTask的類定義:

public FutureTask(Runnable runnable, V result) {
    this.callable = Executors.callable(runnable, result);
    this.state = NEW;       // ensure visibility of callable
}
...
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 {
          //調用Callable的call()
                result = c.call();
                ran = true;
            } catch (Throwable ex) {
                result = null;
                ran = false;
                setException(ex);
            }
            if (ran)
              //將結果保存起來
                set(result);
        }
    } finally {
        // runner must be non-null until state is settled to
        // prevent concurrent calls to run()
        runner = null;
        // state must be re-read after nulling runner to prevent
        // leaked interrupts
        int s = state;
        if (s >= INTERRUPTING)
            handlePossibleCancellationInterrupt(s);
    }
}
複製代碼

FutureTask的參數爲一個runnable與一個Result的對象,FutureTask是一個能夠執行runnable,而且返回執行結果result的類。以前提到,在SerialExecutor中調用了FutureTask的run方法,從上面的run方法定義中能夠看出,其實是調用了傳入的runnable轉換後的Callable的call(),而且將結果保存起來,而後返回:

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

...

private void finishCompletion() {
    ...

    done();
    callable = null;        // to reduce footprint
}
複製代碼

最後經過調用done()方法,表示已經運行完畢。

到這裏咱們發現,實際上最終運行的是FutureTask中的這個Runnable,那麼回到mFutureTask的定義,看到傳入的是一個mWorker,那麼看看mWorker的定義

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
                result = doInBackground(mParams);
                Binder.flushPendingCommands();
            } catch (Throwable tr) {
                mCancelled.set(true);
                throw tr;
            } finally {
                postResult(result);
            }
            return result;
        }
    };
...
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
    Params[] mParams;
}
複製代碼

能夠看到,mWorker就是一個Callable對象,而且在其call()方法內,調用了doInBackground()也就是咱們自定義的後臺操做,在返回結果以後,再調用postResult()返回給主線程:

private Result postResult(Result result) {
    @SuppressWarnings("unchecked")
    Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
            new AsyncTaskResult<Result>(this, result));
    message.sendToTarget();
    return result;
}
複製代碼

能夠看到,postResult內部也是使用handler去返回給主線程的,而後再來看看Handler的定義:

private static class InternalHandler extends Handler {
    public InternalHandler(Looper looper) {
        super(looper);
    }

    @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
            		// 調用finish方法,並將result返回
                result.mTask.finish(result.mData[0]);
                break;
            case MESSAGE_POST_PROGRESS:
                result.mTask.onProgressUpdate(result.mData);
                break;
        }
    }
}
複製代碼

能夠看到,在Handler中調用了finish()這個方法:

private void finish(Result result) {
    if (isCancelled()) {
        onCancelled(result);
    } else {
        onPostExecute(result);
    }
    mStatus = Status.FINISHED;
}
複製代碼

在finish中,將結果返回給用戶,調用咱們自定義的onPostExecute,而且將當前的狀態置爲FINISHED,完成了整個流程。

相關文章
相關標籤/搜索