Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 安卓學習筆記之AsyncTask機制淺析

安卓學習筆記之AsyncTask機制淺析

編輯:關於Android編程

一、相關基礎

1 用途

用於快速開啟異步任務,處理耗時操作。在線程池中處理異步任務,同時可以將進度和處理結果提交到主線程處理。

2 AsyncTask 泛型參數-Params, Progress, Result

Params 表示傳入doInBackground參數的類型
Progress 表示後台任務執行進度的類型
Result 表示後台任務執行完成後返回結果的類型

若不需要傳入具體的參數,傳入Void即可

3 常見方法

onPreExecute 執行任務之前,UI線程,在doInBackground執行之前
doInBackground 執行後台任務,子線程,can call publishProgress to publish updates on the UI thread
onProgressUpdate 進度更新,UI線程
onPostExecute 任務完成時,UI線程
onCancelled 任務取消時,並且onPostExecute不會執行,UI線程

4 幾個重要名詞

InternalHandler AsyncTask內部Handler,處理任務的提交與更新的消息
SerialExecutor 串行線程池,用於任務調度,任務排隊,一次只能執行一個任務
THREAD_POOL_EXECUTOR 線程池的實現者,用於真正執行任務
WorkerRunnable 實現了Callable接口,用於後台計算

5 大致流程

1、 onPreExecute , 執行任務之前,運行在UI線程,在doInBackground執行之前

2、 Result = doInBackground() , 執行後台任務,返回執行結果,在線程池中執行,配合publishProgress來更新任務進度

3、 onProgressUpdate , 在doInBackground方法中調用publishProgress方法,用於進度更新,運行在UI線程(通過內部handler切換到主線程)

4、 onPostExecute , 運行在UI線程,處理運行結果(通過內部handler切換到主線程)

二、 執行流程淺析

1. 首先構造AsyncTask對象,此構造器必須在主線程調用

/**
 * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
 */
public AsyncTask() {
//實例化WorkerRunnable對象
    mWorker = new WorkerRunnable() {
        public Result call() throws Exception {
            mTaskInvoked.set(true);

            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
            //noinspection unchecked
            return postResult(doInBackground(mParams));
        }
    };

// 實例化FutureTask
    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即WorkerRunnable對象,它是一個抽象類,並實現了Callable接口,用於計算一個任務

 private static abstract class WorkerRunnable implements Callable {
    Params[] mParams;
}

mFuture即FutureTask對象,下面用到了如下構造,

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

2. 執行一個任務要從它的execute方法開始

execute方法如下,它調用了executeOnExecutor方法,可以看到默認使用了sDefaultExecutor,即SerialExecutor

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

executeOnExecutor方法,此方法首先檢查運行狀態並賦以新狀態,之後回調onPreExecute方法,並給mWorker賦以參數,最後讓Executor執行任務,並返回AsyncTask對象。

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); // 傳參FutureTask對象

    return this;
}

exec即Executor對象,默認使用SerialExecutor(串行線程池),用於調度任務排隊順序執行。通過exec.execute(mFuture)開啟任務調度,當有任務執行時,其他任務等待。mTasks即ArrayDeque,它是一個雙端隊列。第一次添加任務時,mTasks.offer將新任務添加到任務隊列尾部,此時mActive這個Runnable為空,所以會直接走判斷是否為空中的scheduleNext方法,並在此方法中通過THREAD_POOL_EXECUTOR.execute(mActive)開啟執行任務。後續任務會走finally中的scheduleNext,此時mActive不為空。當執行r.run()方法,即調用了FutureTask對象的run方法

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

FutureTask對象的run方法如下,callable對象即是在構造FutureTask對象時傳入的mWorker,c.call()即在run方法中調用了mWorker的call方法,並將結果保存在result,call方法運行於子線程

public void run() {
    if (state != NEW ||
        !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                     null, Thread.currentThread()))
        return;
    try {
        Callable c = callable;  // callable對象即是在構造FutureTask對象時傳入的mWorker
        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);
    }
}

WorkerRunnable對象的call方法如下,它調用了doInBackground方法並將其返回值作為參數傳給postResult方法。到此調用了doInBackground方法,它運行在線程池中

public Result call() throws Exception {
        mTaskInvoked.set(true);

        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
        //noinspection unchecked
        return postResult(doInBackground(mParams));
    }

postResult方法,它會給AsyncTask內部的InternalHandler發送任務完成信息

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

3. InternalHandler消息處理

InternalHandler如下,當消息類型為MESSAGE_POST_RESULT,通過finish方法完成執行結果的提交。當消息類型為MESSAGE_POST_PROGRESS時,回調更新進度onProgressUpdate方法。通過內部handler切換到主線程

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

finish方法如下,當任務沒有取消時,調用onPostExecute,否則調用onCancelled。都運行在主線程

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

4. 進度更新

publishProgress,在doInBackground方法中調用,用以更新進度。此方法會向InternalHandler發送MESSAGE_POST_PROGRESS消息,以在UI線程更新進度

/**
 * 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.
 *
 * {@link #onProgressUpdate} will note be called if the task has been
 * canceled.
 *
 * @param values The progress values to update the UI with.
 *
 * @see #onProgressUpdate
 * @see #doInBackground
 */
protected final void publishProgress(Progress... values) {
    if (!isCancelled()) {
        sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
                new AsyncTaskResult
(this, values)).sendToTarget(); } }

簡單案例

案例簡單模擬求和運算,並查看各個方法運行的線程
在MainActivity中自定義異步任務類繼承AsyncTask

class BackTask extends AsyncTask {

        @Override
        protected void onPreExecute() {
            Log.e("TAG", "onPreExecute-任務執行之前,當前線程:"+Thread.currentThread().getName());
            super.onPreExecute();
        }

        @Override
        protected Integer doInBackground(Integer... params) {
            Log.e("TAG", "doInBackground-任務執行中... ,當前線程:"+Thread.currentThread().getName());
            int N = params[0];
            int count = 0;
            int total = 0; // 計算總和
            Integer progress = 0; // 進度
            while (count < N) {
                ++count;
                total += count;
                progress = count * 100 / N;
                publishProgress(progress);

            }
            return total;
        }

        @Override
        protected void onPostExecute(Integer result) {
            super.onPostExecute(result);

            Log.e("TAG", "onPostExecute-執行結果,運算總和為" + result+" ,當前線程: "+Thread.currentThread().getName());
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            Log.e("TAG", "onProgressUpdate-當前進度:" + values[0] + "%"+",當前線程:"+Thread.currentThread().getName());
        }
    }

在onCreate方法中開啟任務

new BackTask().execute(100);

運行結果如下

09-07 08:33:53.508: E/TAG(2710): onPreExecute-任務執行之前,當前線程:main
09-07 08:33:53.508: E/TAG(2710): doInBackground-任務執行中... ,當前線程:AsyncTask #2
09-07 08:33:53.578: E/TAG(2710): onProgressUpdate-當前進度:1%,當前線程:main
09-07 08:33:53.578: E/TAG(2710): onProgressUpdate-當前進度:2%,當前線程:main
09-07 08:33:53.578: E/TAG(2710): onProgressUpdate-當前進度:3%,當前線程:main
09-07 08:33:53.578: E/TAG(2710): onProgressUpdate-當前進度:4%,當前線程:main
09-07 08:33:53.578: E/TAG(2710): onProgressUpdate-當前進度:5%,當前線程:main
09-07 08:33:53.578: E/TAG(2710): onProgressUpdate-當前進度:6%,當前線程:main
09-07 08:33:53.578: E/TAG(2710): onProgressUpdate-當前進度:7%,當前線程:main
09-07 08:33:53.578: E/TAG(2710): onProgressUpdate-當前進度:8%,當前線程:main
09-07 08:33:53.578: E/TAG(2710): onProgressUpdate-當前進度:9%,當前線程:main
09-07 08:33:53.578: E/TAG(2710): onProgressUpdate-當前進度:10%,當前線程:main
            ... ... ... ... (省略部分輸出)
09-07 08:33:53.608: E/TAG(2710): onProgressUpdate-當前進度:90%,當前線程:main
09-07 08:33:53.608: E/TAG(2710): onProgressUpdate-當前進度:91%,當前線程:main
09-07 08:33:53.608: E/TAG(2710): onProgressUpdate-當前進度:92%,當前線程:main
09-07 08:33:53.608: E/TAG(2710): onProgressUpdate-當前進度:93%,當前線程:main
09-07 08:33:53.608: E/TAG(2710): onProgressUpdate-當前進度:94%,當前線程:main
09-07 08:33:53.608: E/TAG(2710): onProgressUpdate-當前進度:95%,當前線程:main
09-07 08:33:53.608: E/TAG(2710): onProgressUpdate-當前進度:96%,當前線程:main
09-07 08:33:53.608: E/TAG(2710): onProgressUpdate-當前進度:97%,當前線程:main
09-07 08:33:53.608: E/TAG(2710): onProgressUpdate-當前進度:98%,當前線程:main
09-07 08:33:53.608: E/TAG(2710): onProgressUpdate-當前進度:99%,當前線程:main
09-07 08:33:53.608: E/TAG(2710): onProgressUpdate-當前進度:100%,當前線程:main
09-07 08:33:53.608: E/TAG(2710): onPostExecute-執行結果,運算總和為5050 ,當前線程: main

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