Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android異步處理框架AsyncTask源碼解析

Android異步處理框架AsyncTask源碼解析

編輯:關於Android編程

一.概述

在Android開發中,我們進行異步處理一般會采用兩種方式:
1.Thread +Handler
通常我們在Thread裡面發送消息,然後在Handler的handleMessage方法裡面去處理對應的任務,因為Android是不允許UI線程去更新UI的,這個時候我們可以采取這種方式
2.AsyncTask
AsyncTask是Android為我們封裝的一個輕量級的異步處理框架,其實底層也是用了類似Thread+Handler的方式。對外提供了一些方法,我們實現這些方法就可以很方便的進行異步處理了。

對比

既然兩種方式都可以實現異步處理任務,那麼有什麼區別呢?該使用哪個呢?

1.AsyncTask實現的原理和適用的優缺點
AsyncTask,是android提供的輕量級的異步類,可以直接繼承AsyncTask,在類中實現異步操作,並提供接口反饋當前異步執行的程度(可以通過接口實現UI進度更新),最後反饋執行的結果給UI主線程.
使用的優點:
簡單,快捷
過程可控
使用的缺點:
在使用多個異步操作和並需要進行Ui變更時,就變得復雜起來.
2.Handler異步實現的原理和適用的優缺點
在Handler 異步實現時,涉及到 Handler, Looper, Message,Thread四個對象,實現異步的流程是主線程啟動Thread(子線程)運行並生成Message-Looper獲取Message並 傳遞給HandlerHandler逐個獲取Looper中的Message,並進行UI變更。
使用的優點:
結構清晰,功能定義明確
對於多個後台任務時,簡單,清晰
使用的缺點:
在單個後台異步處理時,顯得代碼過多,結構過於復雜(相對性)
綜上所述:
數據簡單使用AsyncTask:實現代碼簡單,數據量多且復雜使用handler+thread :相比較
AsyncTask來說能更好的利用系統資源且高效 .AsyncTask其實是Android給開發者提供的
一個簡單輕量級的多線程類,通過它我們可以很容易新建一個線程做一些耗時的操作,並在
這個過程中更 新UI。之所以說它輕量級,是因為缺少了直接使用Thread的靈活性。如果是
很復雜的操作,還是建議通過Thread來操作,然後通過 Broadcast的方式來更新UI。

好了,看了兩種方式的區別,我們進入今天的重點,AsyncTask源碼的分析。

二.源碼分析

我們平時會這樣使用AsyncTask,
1.創建一個類繼承AyncTask(因為AsyncTask是抽象的)

 class MyTask extends AsyncTask{
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }
        @Override
        protected String doInBackground(Integer[] params) {
            return null;
        }

        @Override
        protected void onPostExecute(String s) {
            super.onPostExecute(s);
        }
    }

這裡講解兩個地方:
(1)參數
我們看到AsyncTask有三個泛型,Params,Progress,Result,這裡分別為Integer,String,String,每個泛型代表的意思如下
Params:異步任務執行需要傳入的參數類型
Progress:異步任務執行過程中返回進度值的類型
Result:異步任務執行結束後返回結果的類型
(2)方法
這裡我們重寫了三個最常用的方法
onPreExecute:異步任務開始之前做一些初始化的動作,比如初始化進度條,AsyncTask實例創建在哪個線程,這個方法執行在哪個線程
doInBackground:執行後台任務的方法,運行在子線程
onPostExecute:異步任務結束後調用的方法,運行在主線程,通常用來處理結果。

2.執行任務
調用如下方法使異步任務開始執行

//創建AsyncTask對象,調用execute方法
new MyTask().execute();

源碼如下

public abstract class AsyncTask {
    private static final String LOG_TAG = "AsyncTask";
    //獲得當前CPU的核心數
    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    //當前線程池容量 = CPU核心數+1
    private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
   //最大線程池容量 = CPU核心數*2+1
    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
    //當前線程數量大於核心線程數量時,空閒線程在執行任務前等待的最大時間,超過此時間如果還沒有任務則會被終止
    private static final int KEEP_ALIVE = 1;
    //創建新線程需要的線程工廠,需要作為參數傳遞到ThreadPoolExecutor的構造函數中
    private static final ThreadFactory sThreadFactory = new ThreadFactory() {
        private final AtomicInteger mCount = new AtomicInteger(1);

        public Thread newThread(Runnable r) {
        //使用Runnable對象創建線程對象並指定名稱
            return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());//AsyncTask #1
        }
    };
    //用來保存任務的工作隊列,需要作為參數傳遞到ThreadPoolExecutor的構造函數中,此處采用阻塞隊列,遵循FIFO,容量為128,也就是說最多存儲128個任務
    private static final BlockingQueue sPoolWorkQueue =
            new LinkedBlockingQueue(128);
    //根據上面的參數創建線程執行器
    public static final Executor THREAD_POOL_EXECUTOR
            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

     //順序執行任務的Executor
    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
    //發送結果的消息
    private static final int MESSAGE_POST_RESULT = 0x1;
    //發送進度的消息
    private static final int MESSAGE_POST_PROGRESS = 0x2;
    //默認使用順序執行器
    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
    //用來發送消息的InternalHandler
    private static InternalHandler sHandler;

    private final WorkerRunnable mWorker;
    private final FutureTask mFuture;
    //默認掛起狀態,等待任務執行
    private volatile Status mStatus = Status.PENDING;
       //是否取消標志
    private final AtomicBoolean mCancelled = new AtomicBoolean();
    //異步任務對象是否創建標志
    private final AtomicBoolean mTaskInvoked = new AtomicBoolean();
    //串行任務執行器的實現,取出一個個任務交給上面的線程執行器執行
    private static class SerialExecutor implements Executor {
        final ArrayDeque mTasks = new ArrayDeque();
        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);
            }
        }
    }

     //當前任務的狀態
    public enum Status {

        PENDING,//掛起,等待執行
        RUNNING,//正在運行
        FINISHED,//執行結束
    }
    //獲得InternalHandler對象
    private static Handler getHandler() {
        synchronized (AsyncTask.class) {
            if (sHandler == null) {
                sHandler = new InternalHandler();
            }
            return sHandler;
        }
    }

    /** 隱藏方法*/
    public static void setDefaultExecutor(Executor exec) {
        sDefaultExecutor = exec;
    }

    /**
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     */
    public AsyncTask() {
    //創建WorkerRunnable對象,繼承自Callable,重寫call方法
        mWorker = new WorkerRunnable() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);

                //設置線程優先級Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //調用doInBackground,傳入我們的輸入參數
                Result result = doInBackground(mParams);
                Binder.flushPendingCommands();
                //調用postResult方法,傳入doInBackground的結果
                return postResult(result);
            }
        };

        mFuture = new FutureTask(mWorker) {
            @Override
            //任務執行完畢調用此方法
            protected void done() {
                try {
                //如果沒有傳遞任務則進行傳遞,get方法為獲取FutureTask執行完畢的結果
                    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);
                }
            }
        };
    }
    private void postResultIfNotInvoked(Result result) {
        final boolean wasTaskInvoked = mTaskInvoked.get();
        if (!wasTaskInvoked) {//如果沒有傳遞,傳遞結果
            postResult(result);
        }
    }

    .........

接下來我們看看比較重要的一個方法

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

這個方法是干啥的呢?將doInBackground處理的結果封裝成一個AsyncTaskResult對象發送給自定義的Handle對象進行處理,我們可以看到這裡有一個getHandler方法

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

采用了同步鎖的方法來獲取InternalHandler對象,這個Handler對象就是用來處理消息的,我們待會分析,獲得Handler對象後,我們發送了一個msg.obj為如下的消息

new AsyncTaskResult(this, result)

我們去看看這個類

  private static class AsyncTaskResult {
        final AsyncTask mTask;
        final Data[] mData;

        AsyncTaskResult(AsyncTask task, Data... data) {
            mTask = task;
            mData = data;
        }
    }

這個類很簡單,有兩個成員變量,代表當前任務的AsyncTask對象,這裡為this,然後就是數據Data,這裡我們傳遞過來的是doInBackground的處理結果。既然消息發送了,我們看看是如何處理的吧

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

上面先獲取到了發送過來的消息,然後根據消息的類型進行了判斷,進行了不同的處理,如果是投遞結果的消息,執行下面的操作

 result.mTask.finish(result.mData[0]);

result.mTask就是當前的任務,然後調用了finish方法,我們去看看

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

很簡單,首先判斷當前任務是否取消了,如果取消了,就調用onCancelled方法,定義如下

 protected void onCancelled(Result result) {
        onCancelled();
    }

當任務取消的時候會回調onCancelled方法,所以如果我們想要在任務取消的時候做一些操作,可以重寫這個方法。

如果沒有取消,則執行onPostExecute方法,傳入我們的結果,最後將當前任務狀態設置為完成,這裡調用了onPostExecute方法,

至此,我們已經看到了doInbackground和onPostExecute方法的調用之處,那麼還剩下一個onPreExcute方法怎麼沒看到啊?因為我們到目前為止只分析了創建任務實例這個過程所發生的事,任務還沒執行執行呢。

任務執行

執行任務我們會調用execute方法,如果必要的話會傳入參數

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

這裡又調用了executeOnExecutor方法,傳入了sDefaultExecutor和我們的參數,大家還記得sDefaultExecutor是什麼嗎?懶得向上找了,再給大家貼出來吧

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

就是串行執行器,我們去看看executeOnExecutor方法

public final AsyncTask 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;
    }

首先判斷當前狀態,前提是不是掛起狀態,如果正在執行或者已經執行完畢,我們再次調用execute方法就會拋出異常,接下來將當前狀態標記為正在執行,然後調用onPreExecute方法,這裡我們終於看到onPreExecute方法被調用了,然後將我們執行任務時傳入的參數賦值給mWorker的mParams,這個mWorker是啥,之前說過了,

private final WorkerRunnable mWorker;

最後調用sDefaultExecutor 的execute執行任務,並且傳入我們的FutureTask對象。至此,整個過程就完了。

接下來講一些細節性的東西,可能大家也發現有些地方還沒有分析
1.SerialExecutor是如何保證一個任務執行完畢才執行下一個的,我再次把代碼貼出來,給大家分析分析

 private static class SerialExecutor implements Executor {
        final ArrayDeque mTasks = new ArrayDeque();
        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);
            }
        }
    }

首先創建了一個ArrayDeque對象,用來接收我們的消息,然後調用了此對象的offer方法,再裡面調用了execute參數中Runnable對象的run方法,那麼這個Runnable對象是啥啊,如果你仔細閱讀了上面的內容,就會發現這個Runnable對象就是FutureTask,為什麼FutureTask能轉換為Runnable呢,

public class FutureTask implements RunnableFuture 

public interface RunnableFuture extends Runnable, Future {


明白了吧,廢話我就不說了,
那麼我們就去看看FutureTask的run方法

 public void run() {
        if (state != NEW ||
            !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
            return;
        try {
            Callable c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    result = c.call();
                    ran = true;
                    .....

只講重點,這裡將一個callable對象賦值給了一個新的對象,然後調用了call方法,我們看看這個callable對象是在哪裡賦值的

 public FutureTask(Callable callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }

是在FutureTask構造方法裡面復制的,到這大家是不是想起什麼了,是的,我們再AsyncTask中創建鍋Callable的實現類WorkerRunnable並且將其傳給了FutureTask的構造函數,所以,當我們最終調用sDefaultExecutor 的execute方法的時候,就執行了WorkerRunnable中的call方法,call中又調用doInbackground,然後postResult發送消息,又回到了上面的分析。
run執行完畢之後,會判斷mActive是否為空,第一次肯定為空,執行scheduleNext方法

protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }

調用了mTasks的poll方法從當前隊列頭部取出消息,給線程執行器執行,以後mActive就不為null,我們可以看到scheduleNext放到了finally方法裡面,保證了每次都會執行。

好了,AsyncTask的源碼就分析到這裡了,已經快吐血了,費了不少時間,腦子現在還是有點亂,最後大概總結一下下面這句話都干了啥

 new MyTask().execute();

1.創建對象(new MyTask())
創建WorkerRunnable對象(Callable),重寫call方法—->將WorkerRunnable傳遞給FutureTask
2.執行任務(execute())
execute(Params… params)—->executeOnExecutor(Executor exec,
Params… params) —->調用onPreExecute—->調用SerialExecutor的execute方法,傳入上面的FutureTask對象,請注意,這個FutureTask包裝了WorkerRunnable對象,可不簡單哦—->調用FutureTask的run方法(run方法裡面調用了call)—->調用WorkerRunnable的call方法—->調用scheduleNext執行下個任務

最後說一下AsyncTask版本上的差異

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

那麼我們現在有沒有辦法讓AsyncTask並行執行呢》有
在Anddroid3.0以後的AsyncTask類給暴露出一個接口也就是上面的executeOnExecutor方法啦,我們只需要重新構造一個線程池執行器,比如說你可以調用newCachedThreadPool方法來創建一個無線大的緩存線程池,可以同時執行無線個任務。

//構建一個緩存線程池,用於同時執行無限多個異步耗時任務
ExecutorService executorService = Executors.newCachedThreadPool();
asyncTask.executeOnExecutor(executorService,params);

開發者可以根據項目需求選擇自己合適的線程池執行器:

Single Thread Executor : 只有一個線程的線程池,因此所有提交的任務是順序執行,代碼: Executors.newSingleThreadExecutor()

Cached Thread Pool : 線程池裡有很多線程需要同時執行,老的可用線程將被新的任務觸發重新執行,如果線程超過60秒內沒執行,那麼將被終
止並從池中刪除,代碼:Executors.newCachedThreadPool()

Fixed Thread Pool : 擁有固定線程數的線程池,如果沒有任務執行,那麼線程會一直等待,代碼: Executors.newFixedThreadPool()

Scheduled Thread Pool : 用來調度即將執行的任務的線程池,代碼:Executors.newScheduledThreadPool()

Single Thread Scheduled Pool : 只有一個線程,用來調度執行將來的任務,代碼:Executors.newSingleThreadScheduledExecutor()

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