AsyncTask源碼分析(Android7.0)

1.Android 3.0版本之前的AsyncTask

下面是Android 2.3.7版本的AsyncTask的部分源碼。

public abstract class AsyncTask<Params, Progress, Result> {
  private static final String LOG_TAG = "AsyncTask";
  private static final int CORE_POOL_SIZE = 5;
  private static final int MAXIMUM_POOL_SIZE = 128;
  private static final int KEEP_ALIVE = 1;
  private static final BlockingQueue<Runnable> sWorkQueue =
           new LinkedBlockingQueue<Runnable>(10);
  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 ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,
            MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory);

...
}</code></pre>

在這里又看到了ThreadPoolExecutor,它的核心線程數是5個,線程池允許創建的最大線程數為128,非核心線程空閑等待新任務的最長時間為10秒。采用的阻塞隊列是LinkedBlockingQueue,它的容量為10。3.0版本之前的AsyncTask有一個缺點就是,線程池最大的線程數為128,加上阻塞隊列的10個任務,所以AsyncTask最多能同時容納138個任務,當提交第139任務時就會執行飽和策略,默認拋出RejectedExecutionException異常。

2.Android 7.0版本的AsyncTask

在這里采用Android 7.0版本的AsyncTask作為例子,首先來看AsyncTask的構造函數:

public AsyncTask() {
    mWorker = new WorkerRunnable<Params, Result>() {//1
        public Result call() throws Exception {
            mTaskInvoked.set(true);
            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
            Result result = doInBackground(mParams);
            Binder.flushPendingCommands();
            return postResult(result);
        }
    };

mFuture = new FutureTask<Result>(mWorker) {//2
    @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);
        }
    }
};

}</code></pre>

從注釋1處看這個WorkerRunnable實現了Callable<Result>接口,并實現了它的call方法,在call方法中調用了doInBackground(mParams)來處理任務并得到結果,并最終調用postResult將結果投遞出去。注釋2處的FutureTask是一個可管理的異步任務,它實現了Runnable和Futrue這兩個接口。因此它可以包裝Runnable和Callable<V>,并提供給Executor執行。也可以調用線程直接執行(FutureTask.run())。在這里WorkerRunnable作為參數傳遞給了FutureTask。這兩個變量會暫時保存在內存中,稍后會用到它們。

當要執行AsyncTask時,需要調用它的execute方法,代碼如下所示。

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

execute方法又調用了executeOnExecutor方法:

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;//1
    exec.execute(mFuture);
    return this;
}</code></pre> 

這里會首先調用 onPreExecute方法,在注釋1處將AsyncTask的參數傳給WorkerRunnable,從前面我們知道WorkerRunnable會作為參數傳遞給了FutureTask,因此,參數被封裝到FutureTask中。接下來會調用exec的execute方法,并將mFuture也就是前面講到的FutureTask傳進去。這里exec是傳進來的參數sDefaultExecutor,它是一個串行的線程池,它的代碼如下所示。

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() {//1
                public void run() {
                    try {
                        r.run();//2
                    } finally {
                        scheduleNext();
                    }
                }
            });
            if (mActive == null) {
                scheduleNext();
            }
        }
        protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }

從注釋1處可以看出,當調用SerialExecutor 的execute方法時,會將FutureTask加入到mTasks中。當任務執行完或者當前沒有活動的任務時都會執行scheduleNext方法,它會從mTasks取出FutureTask任務并交由THREAD_POOL_EXECUTOR處理。關于THREAD_POOL_EXECUTOR,后面會介紹。從這里看出SerialExecutor是串行執行的。在注釋2處可以看到執行了FutureTask的run方法,它最終會調用WorkerRunnable的call方法。

前面我們提到call方法postResult方法將結果投遞出去,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方法中會創建Message,并將結果賦值給這個Message,通過getHandler方法得到Handler,并通過這個Handler發送消息,getHandler方法如下所示。

private static Handler getHandler() {
    synchronized (AsyncTask.class) {
        if (sHandler == null) {
            sHandler = new InternalHandler();
        }
        return sHandler;
    }
}

在getHandler方法中創建了InternalHandler,InternalHandler的定義如下所示。

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

在接收到MESSAGE_POST_RESULT消息后會調用AsyncTask的finish方法:

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

如果AsyncTask任務被取消了則執行onCancelled方法,否則就調用onPostExecute方法。而正是通過onPostExecute方法我們才能夠得到異步任務執行后的結果。

接著回頭來看SerialExecutor ,線程池SerialExecutor主要用來處理排隊,將任務串行處理。 SerialExecutor中調用scheduleNext方法時,將任務交給THREAD_POOL_EXECUTOR。THREAD_POOL_EXECUTOR同樣是一個線程池,用來執行任務。

private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    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 BlockingQueue<Runnable> sPoolWorkQueue =
            new LinkedBlockingQueue<Runnable>(128);
    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;
    }

THREAD_POOL_EXECUTOR指的就是threadPoolExecutor,他的核心線程和線程池允許創建的最大線程數都是由CPU的核數來計算出來的。它采用的阻塞隊列仍舊是LinkedBlockingQueue,容量為128。

到此, Android 7.0版本的AsyncTask的源碼就分析完了,在AsyncTask中用到了線程池,線程池中運行線程并且又用到了阻塞隊列,因此,本章前面介紹的知識在這一節中做了很好的鋪墊。Android 3.0及以上版本用SerialExecutor作為默認的線程,它將任務串行的處理保證一個時間段只有一個任務執行,而3.0之前版本是并行處理的。關于3.0之前版本的缺點在3.0之后版本也不會出現,因為線程是一個接一個執行的,不會出現超過任務數而執行飽和策略。如果想要在3.0及以上版本使用并行的線程處理可以使用如下的代碼:

asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,"");

其中asyncTask是我們自定義的AsyncTask,當然也可以傳入Java提供的線程池,比如傳入CachedThreadPool。

asyncTask.executeOnExecutor(Executors.newCachedThreadPool(),"");

也可以傳入自定義的線程池:

Executor exec =new ThreadPoolExecutor(0,  Integer.MAX_VALUE,
                0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
   asyncTask.executeOnExecutor(exec,"");

 

來自:http://www.jianshu.com/p/ed7d9fb724cf

 

 本文由用戶 ggtx2404 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!