Android中AsyncTask源碼詳解

AsyncTask類結構分析

public abstract class AsyncTask<Params, Progress, Result> {
    // 下面幾個都是new線程池的一些參數,就不具體解釋了
    private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
    private static final int KEEP_ALIVE_SECONDS = 30;

    private static final ThreadFactory sThreadFactory = new ThreadFactory() {
        private final AtomicInteger mCount = new AtomicInteger(1);

        public Thread newThread(Runnable r) {
            return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
        }
    };

    private static final BlockingQueue<Runnable> sPoolWorkQueue =
            new LinkedBlockingQueue<Runnable>(128);

    // 這個線程池是負責管理任務執行的。注意,是static修飾的,整個應用的所有AsyncTask共用
    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;
    }

    // 任務執行中、執行完成,通過handler通知主線程
    private static InternalHandler sHandler;
    private static final int MESSAGE_POST_RESULT = 0x1;
    private static final int MESSAGE_POST_PROGRESS = 0x2;

    // 這個是存儲任務的線程池,也是static修飾的,所有AsyncTask共用這一個線程池存儲任務
    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

    // 這個是負責執行結果回調的Callback對象(並沒有繼承Runnable)
    private final WorkerRunnable<Params, Result> mWorker;

    // 這個繼承Runnable,負責把doInBackground()方法中的耗時邏輯集成到Runnable中,才能作爲參數傳給線程池
    private final FutureTask<Result> mFuture;
    ......
    ......
    ......
}

這個類裏有兩個線程池,都是static的,全局共享,一個負責存儲Runnable對象,一個負責執行任務,爲了方便後面描述,我們分別命名爲“存儲線程池”和“執行線程池”。

但是線程池只接收Runnable參數,所以需要一個Runnable對象把doInBackground()方法中的代碼集成進去,這樣才能被線程池接收。如何集成?就是在run()方法中調用耗時操作,但是問題又來了,如果把執行結果返回回去呢?

所以又需要WorkerRunnable對象,將耗時操作和執行結果返回封裝一下,在run()方法中調用WorkerRunnable的call()方法。


再看構造方法:

public AsyncTask() {
    // 初始化WorkerRunnable對象,封裝耗時操作和執行結果
    mWorker = new WorkerRunnable<Params, Result>() {
        public Result call() throws Exception {
            mTaskInvoked.set(true);
            Result result = null;
            try {
                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //noinspection unchecked
                // 執行耗時操作
                result = doInBackground(mParams);
                Binder.flushPendingCommands();
            } catch (Throwable tr) {
                 mCancelled.set(true);
                throw tr;
            } finally {
                // 通知掉用處,返回結果
                postResult(result);
            }
            return result;
        }
    };

    // 初始化Runnable對象,與WorkerRunnable綁定,線程池中調用Runnable的run()方法時,就會調用WorkerRunnable的call()方法
    mFuture = new FutureTask<Result>(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);
            }
        }
    };
}


AsyncTask執行流程分析

AsyncTask有兩個重載的execute()方法,一個是默認無參數的,一個是可以自定義Runnable的。先看默認無參數方法:

public final AsyncTask<Params, Progress, Result> execute(Params... params) {
    // 將存儲線程池作爲參數,調用executeOnExecutor()方法
    return executeOnExecutor(sDefaultExecutor, params);
}

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()方法。這個方法是我們在實現AsyncTask時可以重寫的方法,最早執行,用於做一些初始化操作,在UI線程中
    onPreExecute();

    // 將執行參數封裝到WorkerRunnable對象中
    mWorker.mParams = params;
    // 調用存儲線程池的execute()方法,將FutureTask插入存儲線程池中
    exec.execute(mFuture);

    return this;
}

再看有參數、可以自定義Runnable的execute()方法:

public static void execute(Runnable runnable) {
    // 同樣,將runnabale插入存儲線程池中。跟上面的區別就是,上面插入的Runnable對象是默認的,這裏插入的Runnable對象是自定義的
    sDefaultExecutor.execute(runnable);
}


最終都到了存儲線程池sDefaultExecutor的execute()方法,我們看一下SerialExecutor類:

private static class SerialExecutor implements Executor {
    // 使用數組隊列存儲Runnable
    final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
    // 當前正在執行的Runnable
    Runnable mActive;

    public synchronized void execute(final Runnable r) {
        // new要給Runnable,將新任務再次封裝一次,插入到隊列尾部
        // 由於隊列中的任務需要遵循某種邏輯才能依次執行,所以需要重新封裝一次
        mTasks.offer(new Runnable() {
            public void run() {
                try {
                    r.run();
                } finally {
                    scheduleNext();
                }
            }
        });

        // 如果當前Runnable爲null,說明這是該應用第一次執行AsyncTask,需要執行scheduleNext()方法啓動“執行線程池”
        if (mActive == null) {
            scheduleNext();
        }
    }

    protected synchronized void scheduleNext() {
        if ((mActive = mTasks.poll()) != null) {
            // 取出任務,使用執行線程池來執行任務
            THREAD_POOL_EXECUTOR.execute(mActive);
        }
    }
}

從上面的run()方法可以看出,如果是第一次,就調用scheduleNext()啓動任務。如果不是第一次,就把新任務插入到存儲線程池中。上一個任務執行完畢後,會調用scheduleNext()方法執行下一個任務。

這裏需要注意的是,從doInBackground()到最終啓動線程執行耗時操作,中間new了3個Runnable對象。
①第一個Runnable,是爲了把doInBackground()中的邏輯代碼封裝到run()方法中,因爲存儲線程池SerialExecutor統一接收Runnable對象作爲參數;
②第二個Runnable,是爲了把耗時操作封裝到固定邏輯的run()方法中,這樣才能達到依次執行的邏輯;
③第三個Runnable,就是執行線程池中的,真正用來執行耗時操作的,這裏會啓動n個核心線程和n個非核心線程。
前兩個Runnable都是爲了代碼的可擴展性和靈活性做的管道封裝,這兩個Runnable都不會調用start()方法啓動,只是調用run()方法執行裏面的代碼而已。

不管怎樣,最終都會調用FutureTask的run()方法:

public void run() {
    if (state != NEW ||
            !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
        return;
    try {
        // 這個callable就是前面mFuture = new FutureTask<Result>(mWorker)中的WorkerRunnable
        Callable<V> c = callable;
        if (c != null && state == NEW) {
            V result;
            boolean ran;
            try {
                // 調用WorkerRunnable的call()方法
                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);
    }
}


在執行線程池中,會在子線程中調用FutureTask的run()方法,而run()方法中又會調用WorkerRunnable的call()方法,所以call()方法是在子線程中調用的:

public Result call() throws Exception {
        mTaskInvoked.set(true);
        Result result = null;
        try {
            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
            //noinspection unchecked
            //調用doInBackground()方法
            result = doInBackground(mParams);
            Binder.flushPendingCommands();
        } catch (Throwable tr) {
            mCancelled.set(true);
            throw tr;
        } finally {
            // 耗時操作執行完畢後通知結果
            postResult(result);
        }
        return result;
}

private Result postResult(Result result) {
    @SuppressWarnings("unchecked")
    // 通過Handler通知執行結果,這樣就可以在主線程中得到執行結果了
    Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
    message.sendToTarget();
    return result;
}

我們在實現doInBackground()方法時,可以在其中調用publishProgress ()方法通知主線程執行進度:

protected final void publishProgress(Progress... values) {
    if (!isCancelled()) {
        // 同樣,也是通過Handler通知執行進度的
        getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                new AsyncTaskResult<Progress>(this, values)).sendToTarget();
    }
}

另外,如果我們啓動任務時,調用execute(Runnable runnable)方法,使用自定義的Runnable,那最終就只會調用自定義Runnable的run()方法,系統就無法幫我們回調doInbackGround()、postResult()方法,需要我們自己在run()方法中實現耗時操作的處理、結果返回的處理。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章