Android線程和線程池---AsyncTask源碼分析

1、AsyncTask源碼分析

1、構造方法

先看構造方法,在類初始化的時候,創(chuàng)建了Callable對象和FutureTask對象,并用FutureTask對象來包裝Callable對象,call()方法將做為線程的執(zhí)行體。

    private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
        Params[] mParams;
    }
    public AsyncTask() {
        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                //當前任務已被調用過
                mTaskInvoked.set(true);
                try {
                    ...
                    result = doInBackground(mParams);
                } catch (Throwable tr) {
                    ...
                } finally {
                    postResult(result);
                }
                return result;
            }
        };

        mFuture = new FutureTask<Result>(mWorker) {...};
    }

但是為什么要使用FutureTask和Callable,直接使用Runnable不可以嗎?

2、InternalHandler

postResult()方法會通過InternalHandler,向主線程發(fā)送一個MESSAGE_POST_RESULT消息;InternalHandler收到消息后,會調用AsyncTask的finish()方法,然后就可以將結果傳遞給onPostExecute()方法了。

    private Result postResult(Result result) {
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }

InternalHandler,用于將執(zhí)行環(huán)境從線程池,切換到主線程

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

    private static class InternalHandler extends Handler {
        public InternalHandler() {
            super(Looper.getMainLooper());
        }
        @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;
            }
        }
    }

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

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

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

從以上代碼中我們可以看到,sHandler是一個靜態(tài)的Handler對象。我們知道創(chuàng)建Handler對象時需要當前線程的Looper,所以我們?yōu)榱艘院竽軌蛲ㄟ^sHandler將執(zhí)行環(huán)境從后臺線程切換到主線程(即在主線程中執(zhí)行handleMessage方法),我們必須使用主線程的Looper,因此必須在主線程中創(chuàng)建sHandler。這也就解釋了為什么必須在主線程中加載AsyncTask類,是為了完成sHandler這個靜態(tài)成員的初始化工作。

3、execute()方法

execute()方法接收的參數是Params類型的參數,這個參數會一路傳遞到doInBackground方法中;通過execute()方法,可以將FutureTask對象添加到線程池(SerialExecutor)中

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

如下,當AsyncTask對象的當前狀態(tài)為RUNNING或FINISHED時,調用execute方法會拋出異常,這意味著不能對正在執(zhí)行任務的AsyncTask對象或是已經執(zhí)行完任務的AsyncTask對象調用execute方法,這就是‘一個AsyncTask對象只能調用一次execute方法’的原因

    @MainThread
    public final AsyncTask<Params, Progress, Result> 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;
    }

AsyncTask有兩個線程池:sDefaultExecutor (SerialExecutor)、THREAD_POOL_EXECUTOR。
sDefaultExecutor,是一個串行的線程池,主要是把任務加到任務緩存隊列中;THREAD_POOL_EXECUTOR用于真正的執(zhí)行任務

  • mTask代表這個線程池的任務緩存隊列,我們可以使用offer()方法向這個隊列添加任務。
  • mActive代表當前正在執(zhí)行的任務,可以通過mTasks.poll()取出一個任務,使用THREAD_POOL_EXECUTOR.execute(mActive);執(zhí)行這個任務,這時后臺任務便開始你真正執(zhí)行了。

THREAD_POOL_EXECUTOR線程池,會執(zhí)行mTasks中的run()方法——>mFuture的run()方法——>Callable的call()方法——>doInBackground()方法

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

2、AsyncTask的簡單使用

        AsyncTask asyncTask=new AsyncTask<String, Integer, Void>() {
            @Override
            protected void onPreExecute() {}
            @Override
            protected void onPostExecute(Void aVoid) { }
            @Override
            protected void onProgressUpdate(Integer... values) {}
            @Override
            protected Void doInBackground(String... params) { return null;}}
      .execute("");
  • onPreExecute():在主線程中進行,在異步任務開始之前調用
  • doInBackground()在線程池中執(zhí)行,用于執(zhí)行異步任務
  • onProgressUpdate():在主線程中進行,在異步任務執(zhí)行進度發(fā)生變化時調用
  • **onPostExecute() **:在主線程中進行,在異步任務執(zhí)行完調用

3、 AsyncTask的局限性

AsyncTask的優(yōu)點在于執(zhí)行完后臺任務后可以很方便的更新UI,然而使用它存在著諸多的限制

  • 在Android 4.1版本之前,AsyncTask類必須在主線程中加載,這意味著對AsyncTask類的第一次訪問必須發(fā)生在主線程中;在Android 4.1以及以上版本則不存在這一限制,因為ActivityThread(代表了主線程)的main方法中會自動加載AsyncTask

  • AsyncTask對象要在主線程中創(chuàng)建

  • execute()方法要在主線程調用

  • 一個AsyncTask對象對象只能執(zhí)行一次execute()方法

  • 內存泄漏:如果AsyncTask被聲明為Activity的非靜態(tài)的內部類,那么AsyncTask會保留一個對創(chuàng)建了AsyncTask的Activity的引用。如果Activity已經被銷毀,AsyncTask的后臺線程還在執(zhí)行,它將繼續(xù)在內存里保留這個引用,導致Activity無法被回收,引起內存泄露。

</br></br>

參考:Android開發(fā)藝術探討、深入理解AsyncTask的工作原理

</br></br>

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容