AsyncTask源码解析,你需要摸清的细节

来源:互联网 发布:道士嗜血术数据 编辑:程序博客网 时间:2024/04/28 20:05

AsyncTask简介

1. AsyncTask提供了一种恰当的简单的跟UI Thread交互的方式。
2. 它不需要通过操控Threads或Handler就可以将后台操作以及其结果展示在UI Thread上。
3. AsyncTask是围绕Thread和Handler被设计出的一个Helper类,它不构成一般的线程框架。
4. AsyncTasks使用在短时间操作(最多几秒钟)上是非常理想的。
5. 如果你需要保持一个长时间操作,强烈建议还是使用java.util.concurrent包中的类,比如Executor、ThreadPollExecutor和FutureTask。

如何定义一个Asynchronous Task

1. 需要在后台进行计算
2. 结果要被public到UI Thread上。

定义Asynchronous Task的三个元素

1. Params 参数
2. Progress 进度
3. Result 结果

定义Asynchronous Task的4个步骤

1. onPreExecute
2. doInBackground
3. onProgressUpdate
4. onPostExecute

范例

1. 类的实现

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

2. 执行

new DownloadFilesTask().execute(url1, url2, url3);

3. 取消Task

Async Task可以通过cancel(boolean)在任何时间cancel.在cancel之后,isCancelled()返回的函数会变成true。
在cancel函数被调用后,onCancelled(Object)会替代onPostExecute(Object)在doInBackground(Object[])之后被调用,
注.如果要尽快确定task被cancelled,要周期性的不断在doInBackground(Object[])检查isCancelled(), 
可以在里头内置一个 循环,不断的查询。

4. 使用规则

1. AsyncTask类必须在UI线程中被实例化
2. AsyncTask必须在UI线程中被创建
3. execute(Params...) 必须在UI线程中被调用
4. 不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法;
5. task只能被执行一次,否则多次调用时将会出现异常;

Memory可观察性

AsynTask保证所有回调调用不用加synchronized也是线程安全的。
1. Set member fields in the constructor or onPreExecute(), and refer to them in doInBackground(Params...).
2. Set member fields in doInBackground(Params...), and refer to them in onProgressUpdate(Progress...) and onPostExecute(Result).

顺序执行,演变史

1. 在刚被Google引入使用时,AsyncTasks会被线性的在单一线程里头执行。
2. 从Android 2.0DONUT开始, AsyncTasks改进到在线程池中,并允许多线程并发执行 
3. 从Andriod 3.0HONEYCOMB开始, tasks在单一线程中执行以避免因并发Exception导致一般的应用错误
4. 如果你一定要并发执行,可以通过executeOnExecutor(java.util.concurrent.Executor, Object[])函数,在THREAD_POOL_EXECUTOR中执行(线程池).

源码解析

1. 先说下有几个需要实现的

    protected abstract Result doInBackground(Params... params);    protected void onPreExecute() {    }    @SuppressWarnings({"UnusedDeclaration"})    protected void onPostExecute(Result result) {    }    @SuppressWarnings({"UnusedDeclaration"})    protected void onProgressUpdate(Progress... values) {    }

2. 先看结构体

public AsyncTask() {        mWorker = new WorkerRunnable<Params, Result>() {            public Result call() throws Exception {                mTaskInvoked.set(true);                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);                //noinspection unchecked                return postResult(doInBackground(mParams));            }        };        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 occured while executing doInBackground()",                            e.getCause());                } catch (CancellationException e) {                    postResultIfNotInvoked(null);                }            }        };    }
在这里实例化了WorkerRunnable并将赋值给mWorker;将mWorker作为参数以实例化FutureTask,赋值给mFuture.

3. 再看如何execute

    public final AsyncTask<Params, Progress, Result> execute(Params... params) {        return executeOnExecutor(sDefaultExecutor, params);    }    public static void execute(Runnable runnable) {        sDefaultExecutor.execute(runnable);    }
AsyncTask有两个execute。可以看到莫名情况下execute会直接以mDefaultExecutor为参数调用executeOnExecutor()。
直接运行runnable,mDefaultExecutor也会直接执行一个runnable。
    看下sDefaultExecutor
    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
    再跟
    /**     * An {@link Executor} that executes tasks one at a time in serial     * order.  This serialization is global to a particular process.     */    public static final Executor SERIAL_EXECUTOR = 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);            }        }    }

    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();    private static final int CORE_POOL_SIZE = CPU_COUNT + 1;    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;    private static final int KEEP_ALIVE = 1;    /**     * An {@link Executor} that can be used to execute tasks in parallel.     */    public static final Executor THREAD_POOL_EXECUTOR            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
THREAD_POOL_EXECUTOR看来google在3.0之后,对ThreadPoolExecutor进行的优化,会考虑到当前硬件配置而行。
这里的配置方案倒是挺符合惯例的。要注意之类KEEP_ALIVE = 1.单线程运行。
sDefaultExecutor是个线性Executor。先将Task加载进ArrayDeque,再一个个poll出来,用THREAD_POOL_EXECUTOR执行。

4. 回到之前的execute流程。看executeOnExecutor

 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;    }
分析一下,
mStatus有三个状态
    public enum Status {        /**         * Indicates that the task has not been executed yet.         */        PENDING,        /**         * Indicates that the task is running.         */        RUNNING,        /**         * Indicates that {@link AsyncTask#onPostExecute} has finished.         */        FINISHED,    }
通过mStatus的状态来判断是否要抛出Exception,可以看出,正在运行的Task不能被再次运行,已经运行过的task不能再次被运行。
设置好mStatus的状态之后,会调用abstract onPreExecute().并调整mWorker的mParams;然后才在executor中执行mFuture,开始真正的运算。

5. 回头再看下mWorker的实例化

    在executor调用execute(mFuture)之后,就会调用。doInBackground
    protected abstract Result doInBackground(Params... params);

6. 那publishProgress什么时候调用呢?

    在doInBackground的函数实现的时候,可以调用publishProgress及时更新状态。progress的进度需要手动实现。
    
protected final void publishProgress(Progress... values) {        if (!isCancelled()) {            getHandler().obtainMessage(MESSAGE_POST_PROGRESS,                    new AsyncTaskResult<Progress>(this, values)).sendToTarget();        }    }    private static class InternalHandler extends Handler {        ...        @Override        public void handleMessage(Message msg) {            AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;            switch (msg.what) {                ....                case MESSAGE_POST_PROGRESS:                    result.mTask.onProgressUpdate(result.mData);                    break;            }        }    }
    通过Handler调用onProgressUpdate.

7. 再看mWorker的实例化。在doInBackground完成之后,会postResult

 private Result postResult(Result result) {        @SuppressWarnings("unchecked")        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,                new AsyncTaskResult<Result>(this, result));        message.sendToTarget();        return result;    }     @SuppressWarnings({"RawUseOfParameterizedType"})    private static class AsyncTaskResult<Data> {        final AsyncTask mTask;        final Data[] mData;        AsyncTaskResult(AsyncTask task, Data... data) {            mTask = task;            mData = data;        }    }private static class InternalHandler extends Handler {        ...        @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;                ....            }        }    }
    再跟
    private void finish(Result result) {        if (isCancelled()) {            onCancelled(result);        } else {            onPostExecute(result);        }        mStatus = Status.FINISHED;    }
    可以看到。如果没有被cancel掉,那么会就调用onPostExecute。不然就会调用onCancelled。mStatus的状态也会被更新为Status.FINISHED

    小结,至此AsyncTask的execute流程就完结。

8. 中止Task

    public final boolean cancel(boolean mayInterruptIfRunning) {        mCancelled.set(true);        return mFuture.cancel(mayInterruptIfRunning);    }
    mCancelled的标识被设置成true。再将mFuture给取消掉。

    继续跟,看下mCancelled是如何使用的?
    public final boolean isCancelled() {        return mCancelled.get();    }
    看isCancelled()是如何使用?
    protected final void publishProgress(Progress... values) {        if (!isCancelled()) {            getHandler().obtainMessage(MESSAGE_POST_PROGRESS,                    new AsyncTaskResult<Progress>(this, values)).sendToTarget();        }    }
    假如mCancelled被设置成true,那么将不会继续更新状态。
    private void finish(Result result) {        if (isCancelled()) {            onCancelled(result);        } else {            onPostExecute(result);        }        mStatus = Status.FINISHED;    }
    当mFuture被cancel掉之后,运算就结束了。postResult就会被调用。通过MESSAGE_POST_RESULT会调用finish。
    按照finish的逻辑,onCancelled就会被顺利调用
    至此,cancel的流程就完成。

结束

AsyncTask,其实就是个利用ThreadPoolExecutor。Future。Handler实现的可以更新。
在5个使用规则的前提下,AsyncTask就可以顺利更新UI。
换言之,AsyncTask如果你不用View的更新.理论上是可以在分线程上用.可以从中了解AsyncTask的设计理念.
0 0
原创粉丝点击