源碼分析Android AsyncTask

來源:互聯網
上載者:User

Android UI操作是線程不安全的,若想在子線程紅進行UI操作,需要藉助Android提供的Handler。Android提供的AsyncTask其實是對Handler的封裝,方便我們在子線程中更新UI元素。AsyncTask是一個泛型類,書寫格式為: AsyncTask。這三個參數的用途如下:

1. Params

這三個參數的用途如下:
1. Params
在執行AsyncTask時需要傳入的參數,可用於在背景工作中使用。
2. Progress
背景工作執行時,如果需要在介面上顯示當前的進度,則使用這裡指定的泛型作為進度單位。
3. Result
當任務執行完畢後,如果需要對結果進行返回,則使用這裡指定的泛型作為返回值類型。

Android SDK中給出的一個AsyncTask用法如下:

 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().execute(url1, url2, url3);

AsyncTask是個抽象類別,有四個方法需要被重寫,這四個方法的的調用過程如下:
第1步. onPreExecute()方法會在背景工作開始執行之間調用,用於進行一些介面上的初始化操作。
第2步. doInBackground(Params...)方法中的所有代碼都會在子線程中運行,我們應該在這裡去處理所有的耗時任務。任務一旦完成就可以通過return語句來將任務的執行結果進行返回。如果需要更新UI元素,比如說反饋當前任務的執行進度,可以調用publishProgress(Progress...)方法來完成。
第3步. 當在背景工作中調用了publishProgress(Progress...)方法後,onProgressUpdate(Progress...)方法就很快會被調用,方法中攜帶的參數就是在背景工作中傳遞過來的。在這個方法中可以對UI進行操作,利用參數中的數值就可以對介面元素進行相應的更新。
第4步. 當背景工作執行完畢並通過return語句進行返回時,onPostExecute(Result)很快會被調用。此處可以
進行UI操作。

AsyncTask的源碼
當初使用AsyncTask的時候,一直不明白onProcessUpdate為何會定期被調用。後來在工作中要實現一個定時更新任務進度的功能,我們用的是一個Handler給自己發送訊息來進行定時重新整理。現在研究了一下AsyncTask的實現原理,發現它也是使用Handler給自己發送訊息的原理來實現定時重新整理。當我選用的是Android 4.4的源碼,若大家能搞懂AsyncTask的實現原理,也能自己寫一個簡單的AsyncTask。
首先看看建構函式:注意,建構函式一定要在UI中調用。

   /**     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.     */    public AsyncTask() {        mWorker = new WorkerRunnable() {            public Result call() throws Exception {                mTaskInvoked.set(true);                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);                //noinspection unchecked                return postResult(doInBackground(mParams));            }        };        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 occured while executing doInBackground()",                            e.getCause());                } catch (CancellationException e) {                    postResultIfNotInvoked(null);                }            }        };    }
這個函數初試化了兩個變數:mWorker和mFuture。mWorker是一個Callable對象,mFuture是一個實現了Runnable和Future的對象。啟動AsyncTask調用的是execute(Params)
    public final AsyncTask execute(Params... params) {        return executeOnExecutor(sDefaultExecutor, params);    }
該方法調用了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;    }
該方法先設定運行狀態,然後調用onPreExecute,最後調用exec.execute(mFuture).傳入的exec是sDefaultExecutor, sDefaultExecutor是一個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);            }        }    }
當調用sDefaultExecutor.execute(runnable),該方法用一個ArrayDeque來儲存runnable,runnable會在合適的時候被調用。第一次運行mActivity等於null了,於是會調用scheduleNext()方法。在這個方法中會從隊列的頭部取值,並賦值給mActive對象,然後調用THREAD_POOL_EXECUTOR去執行取出的取出的Runnable對象。這裡使用了一個try finally代碼塊,並在finally中調用了scheduleNext()方法,每次當一個任務執行完畢後,下一個任務才會得到執行,SerialExecutor模仿的是單一線程池的效果,如果我們快速地啟動了很多任務,同一時刻只會有一個線程正在執行,其餘的均處於等待狀態。

sDefaultExecutor.execute(Runnable)傳入的對象是mFuture,mFuture是一個FutureTask對象,其建構函式如下所示:

 public FutureTask(Callable callable) {        if (callable == null)            throw new NullPointerException();        this.callable = callable;        this.state = NEW;       // ensure visibility of callable    }
由AsyncTask的建構函式可知,FutureTask中的callable是mWorkder對象。FutureTask的run()代碼如下所示:
    public void run() {        if (state != NEW ||            !UNSAFE.compareAndSwapObject(this, runnerOffset,                                         null, Thread.currentThread()))            return;        try {            Callable 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 {            // 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);        }    }
因此,最終會調用mWorker的call()。mWorker的call()位於AsyncTask的建構函式中,大家可以發現其先調用doInBackgroud(Params),然後調用postResult().postResult(Result)的原始碼如下:

    private Result postResult(Result result) {        @SuppressWarnings("unchecked")        Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,                new AsyncTaskResult(this, result));        message.sendToTarget();        return result;    }
sHandler是一個InternalHandler,代碼如下:

 private static class InternalHandler extends Handler {        @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()方法,如果這是一條MESSAGE_POST_PROGRESS訊息,就會去執行onProgressUpdate()方法。當我們在doInBackgroud(Params)中利用for迴圈來調用publishProgress(Progress... values),就會類比出
定時調用onProgressUpdate(Progress... values)的效果。publishProgress(Progress... values)的源碼如下:

    protected final void publishProgress(Progress... values) {        if (!isCancelled()) {            sHandler.obtainMessage(MESSAGE_POST_PROGRESS,                    new AsyncTaskResult(this, values)).sendToTarget();        }    }
它首先會判斷線程是否已經結束,若沒結束,則sHandler給自己發送一個訊息,訊息的類型為MESSAGE_POST_PROGRESS,sHandler.handleMessage(Message)則會調用onProgressUpdate(Progress... values)。
由上可知sDefaultExecutor先調用mFuture的run(), 而mFuture的run()又會調用mWorker的call()。當執行完一個任務後,mFuture的done()會被回調。done()會調用ppostResultIfNotInvoked(Result result),源碼如下:

    private void postResultIfNotInvoked(Result result) {        final boolean wasTaskInvoked = mTaskInvoked.get();        if (!wasTaskInvoked) {            postResult(result);        }    }
postResult(Result)已經在前面有過講解,在此不再贅述。






聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.