Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android中AsyncTask基本用法與源碼剖析(API 23)

Android中AsyncTask基本用法與源碼剖析(API 23)

編輯:關於Android編程

Android的UI是線程不安全的,想在子線程中更新UI就必須使用Android的異步操作機制,直接在主線程中更新UI會導致程序崩潰。
Android的異步操作主要有兩種,AsyncTask和Handler。AsyncTask是一個輕量的異步類,簡單、可控。本文主要結合API 23的源碼講解一下AsyncTask到底是什麼。

基本用法

聲明:Android不同API版本中同一個類的實現方法可能會有不同,本文是基於最新的API 23的源碼進行講解的。

public abstract class AsyncTask

Params:執行時傳入的參數
Progress:後台任務的執行進度
Result:返回值

AsyncTask是個抽象類,所以需要自己定義一個類繼承他,比如

class MyAsyncTask extends AsyncTask

AsyncTask的執行過程:

execute(Params… params),執行異步任務。 onPreExecute(),在execute(Params… params)被調用後執行,界面上的初始化操作,比如顯示一個進度條對話框等。 doInBackground(Params… params),在onPreExecute()完成後執行,用於執行較為費時的操作,如果AsyncTask的第三個泛型參數指定的是Void,就可以不返回任務執行結果。在執行過程中可以調用publishProgress(Progress… values)來更新進度信息。注意,此方法中不可以進行UI操作。 onProgressUpdate(Progress… values),調用publishProgress(Progress… values)時,此方法被執行,將進度信息更新到UI組件上。 onPostExecute(Result result),當後台操作結束時,此方法將會被調用,計算結果將做為參數傳遞到此方法中,可以利用返回的數據來進行一些UI操作,比如說提醒任務執行的結果,以及關閉掉進度條對話框等。

示例

新建一個Activity,一個Button和一個ProgressBar,點擊Button啟動一個AsyncTask並實時更新ProgressBar的狀態。

MyAsyncTask

class MyAsyncTask extends AsyncTask {

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }

        @Override
        protected void onPostExecute(Boolean aBoolean) {
            super.onPostExecute(aBoolean);
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            progressBar.setProgress(values[0]);
        }

        @Override
        protected Boolean doInBackground(Void... params) {
            for (int i = 0; i < 100; i++) {
                //調用publishProgress,觸發onProgressUpdate方法
                publishProgress(i);
                try {
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            return true;
        }

        @Override
        protected void onCancelled() {
            super.onCancelled();
            progressBar.setProgress(0);
        }
    }

Button的Click方法

startAsyncBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                myAsyncTask = new MyAsyncTask();
                myAsyncTask.execute();
            }
        });

源碼剖析

通過上面的例子可以發現,AsyncTask使用起來很簡單,很方便的就可以在主線程中新建一個子線程進行UI的更新等操作。但是他的實現並不像使用起來那麼簡單,下面就是對AsyncTask的源碼進行剖析。

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

在構造函數中只做了兩件事,初始化mWorker和mFuture兩個變量。mWorker是一個Callable對象,mFutre是一個FutureTask對象。execute()時會用到。

execute(Params… params)

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

只有一行代碼,調用了executeOnExecutor方法,sDefaultExecutor實際上是一個串行的線程池,一個進程中所有的AsyncTask全部在這個串行的線程池中排隊執行。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)下面分析一一下線程池的執行過程。

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

系統先把AsyncTask的Params參數封裝為FutureTask對象,FutureTask是一個並發類,這裡它相當於Runnable;接著將FutureTask交給SerialExecutor的execute方法,它先把FutureTask插入到任務隊列tasks中,如果這個時候沒有正在活動的AsyncTask任務,那麼就會執行下一個AsyncTask任務,同時當一個AsyncTask任務執行完畢之後,AsyncTask會繼續執行其他任務直到所有任務都被執行為止。從這裡就可以看出,默認情況下,AsyncTask是串行執行的
看一下AsyncTask的構造函數,mFuture構造時是把mWork作為參數傳進去的,mFuture的run方法會調用mWork的call()方法,因此call()最終會在線程池中執行。call()中調用了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中通過getHandler()獲得一個Handler。

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

查看getHandler源碼,可以發現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;
            }
        }
    }

看到這裡已經豁然開朗了,InternalHandler是一個繼承Handler的類,在他的handleMessage()方法中對msg進行了判斷,如果是MESSAGE_POST_RESULT就執行finish(),如果是MESSAGE_POST_PROGRESS,就執行onProgressUpdate()。
MESSAGE_POST_PROGRESS消息是在publishProgress裡發出的,詳情見源碼。

protected final void publishProgress(Progress... values) {
        if (!isCancelled()) {
            getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                    new AsyncTaskResult
(this, values)).sendToTarget(); } }

finish()

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

如果當前任務被取消,就調用onCancelled()方法,如果沒有調用onPostExecute()。

注意事項

AsyncTask的類必須在主線程中加載,這個過程在Android 4.1及以上版本中已經被系統自動完成。 AsyncTask對象必須在主線程中創建,execute方法必須在UI線程中調用。一個AsyncTask對象只能執行一次,即只能調用一次execute方法,否則會報運行時異常。

各個版本的區別

在Android 1.6之前,AsyncTask是串行執行任務的,Android 1.6的時候AsyncTask開始采用線程池並行處理任務,但是從Android 3.0開始,為了避免AsyncTask帶來的並發錯誤,AsyncTask又采用一個線程來串行執行任務。盡管如此,在Android 3.0以及後續版本中,我們可以使用AsyncTask的executeOnExecutor方法來並行執行任務。但是這個方法是Android 3.0新添加的方法,並不能在低版本上使用。

總結

整個AsyncTask的源碼已經剖析完了,在分析完真個源碼後可以發現,AsyncTask並沒有什麼神秘的,他的本質就是Handler
我們現在已經知道了AsyncTask如何使用,各個方法會在什麼時候調用,有什麼作用,相互之間有什麼聯系,相信大家以後在遇到AsyncTask的任何問題都不會再害怕了,因為AsyncTask的整個源碼都翻了個底朝天,還有什麼好怕的呢。

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