Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> AsyncTask(二)AsyncTask源碼分析(基於android-24)

AsyncTask(二)AsyncTask源碼分析(基於android-24)

編輯:關於Android編程

前言:

雖然現在RxJava非常流行,但是還是覺得應該分析一下Android的原生異步線程實現。打算用2篇文章來過一下這個知識點。其中第一部分主要為使用例子,第二部分從源碼的角度來驗證那樣使用的原因。

第一篇

第二篇

我分析一個類的時候,都是習慣先看它有哪些成員,然後從入口開始慢慢理順成員間的邏輯。

有一條捷徑是先看Android API文檔,上面各個類都有總結,然後再看代碼。

這裡是API地址

AsyncTask的類結構如下:

 

內部類:
private static class SerialExecutor implements Executor  //串行執行器
public enum Status {PENDING, RUNNING, FINISHED} //task的三種狀態
private static class InternalHandler extends Handler //內部封裝的Handler
private static abstract class WorkerRunnable implements Callable //工作線程
private static class AsyncTaskResult 

構造方法:public AsyncTask()   //初始化了工作線程和執行回調
重要成員:
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();//CPU核數
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));//核心線程數 2-4之間
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;//最大線程數
private static final int KEEP_ALIVE_SECONDS = 30;//生存時間
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();//串行執行器
//Handler的2個消息類型, 0x1執行完畢, 0x2進度更新
private static final int MESSAGE_POST_RESULT = 0x1;
private static final int MESSAGE_POST_PROGRESS = 0x2;
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;//可以外部設置的執行器,默認是串行執行器
private static InternalHandler sHandler;//內部封裝的Handler,處理上面的2個消息
private final WorkerRunnable mWorker;//工作線程
private volatile Status mStatus = Status.PENDING;//task當前狀態,初始值為 PENDING

 

對外提供的接口:
//下面3個executr都只能在UI線程中調用
public final AsyncTask execute(Params... params) //串行執行器
public final AsyncTask executeOnExecutor(Executor exec,Params... params) //自定義執行器,可以設置參數做並行計算

官方注釋如下

 

This method is typically used with {@link #THREAD_POOL_EXECUTOR} to
* allow multiple tasks to run in parallel on a pool of threads managed by
* AsyncTask, however you can also use your own {@link Executor} for custom
* behavior.

 


public final boolean isCancelled() 
public final boolean cancel(boolean mayInterruptIfRunning)
public final Result get() throws InterruptedException, ExecutionException //獲取執行結果
public final Status getStatus()
public static void setDefaultExecutor(Executor exec) //設置自己的執行器


下面從AsyncTask的3個入口來分析它。

 

第一個串行執行入口:

 

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

 

executeOnExecutor如下:

 

 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;


 

 


從這裡可以看出為什麼execute只能調用一次,第二次調用的時候就會throw new IllegalStateException。

 

在執行execute前會先調用onPreExecute。

execute內容如下,

 

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

從run方法可以看出來,execute方法加了鎖,只有當r.run()執行完畢後,才會scheduleNext執行下一個Runnable。

因此THREAD_POOL_EXECUTOR中的Runnable是串行執行的。

此外,可以看到,實際上execute是通過調用executeOnExecutor實現的,只不過指定傳入了串行執行器。

 

我們仍可以給executeOnExecutor傳入其它執行器來實現並行計算,

AsyncTask內部就維護了一個Java線程池,

 

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

它的關鍵變量之前已經列過:

 

 

private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));//核心線程數 2-4之間
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;//最大線程數
private static final int KEEP_ALIVE_SECONDS = 30;//生存時間

我們可以直接傳入這個線程池來進行並行計算。

 

最後一個,

 

 public static void execute(Runnable runnable) {
        sDefaultExecutor.execute(runnable);
    }
它實際上也是調用是串行執行器來執行的,這不過是免去了不需要部分的初始化工作。

 

 

public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

 


回到AsyncTask的構造函數:

 

 public AsyncTask() {
        mWorker = new WorkerRunnable() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);

                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //noinspection unchecked
                Result result = doInBackground(mParams);
                Binder.flushPendingCommands();
                return postResult(result);
            }
        };

        mFuture = new FutureTask(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);
                }
            }
        };
    }

工作線程的RUN方法中,doInBackGround()之後會調用postResult

 

 

 private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult(this, result));
        message.sendToTarget();
        return result;
    }
在postResult中會發出消息通知Handler,

 

 

     case MESSAGE_POST_RESULT:
                    // There is only one result
                    result.mTask.finish(result.mData[0]);
                    break;

Handler會去調用finsh方法

 

 

private void finish(Result result) {
        if (isCancelled()) {
            onCancelled(result);
        } else {
            onPostExecute(result);
        }
        mStatus = Status.FINISHED;
    }
finish會去調用onCancelled或者onPostExecute方法。

 

至此,AsyncTask的3個Step已經走過了。

onPreExecute -> doInBackGround -> onPostExecute

怎麼還少了一個onProgressUpdate呢?

 

直接找到onProgressUpdate的調用處,

 

 case MESSAGE_POST_PROGRESS:
       result.mTask.onProgressUpdate(result.mData);
       break;
Handler在收到消息MESSAGE_POST_PROGRESS的時候會去調用onProgressUpdate

 

這個消息哪裡發的呢?是在publishProgress方法中

 

 protected final void publishProgress(Progress... values) {
        if (!isCancelled()) {
            getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                    new AsyncTaskResult
(this, values)).sendToTarget(); } }
可是publishProgress並沒有被任何地方調用到啊

 

還是要靠官方注釋

This method can be invoked from {@link #doInBackground} to
     * publish updates on the UI thread while the background computation is
     * still running. Each call to this method will trigger the execution of
     * {@link #onProgressUpdate} on the UI thread.

 

這個方法要在doInBackGround中調用,而doInBackGround是一個抽象方法,要靠用戶自己去實現。

所以,其實谷歌並沒有幫你把所有事情都做好,至少沒有幫你計算線程進度。

這個進度還是要我們自己來算。

到此,AsyncTask的整個流程都很清楚了。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved