AsyncTask源码解析

来源:互联网 发布:淘宝神评论 编辑:程序博客网 时间:2024/06/06 01:32

AsyncTask 是Android  SDK中的一个类,相信大家都是用过,看下源码中的注释

/** * <p>AsyncTask enables proper and easy use of the UI thread. This class allows you * to perform background operations and publish results on the UI thread without * having to manipulate threads and/or handlers.</p> * * <p>AsyncTask is designed to be a helper class around {@link Thread} and {@link Handler} * and does not constitute a generic threading framework. AsyncTasks should ideally be * used for short operations (a few seconds at the most.) If you need to keep threads * running for long periods of time, it is highly recommended you use the various APIs * provided by the <code>java.util.concurrent</code> package such as {@link Executor}, * {@link ThreadPoolExecutor} and {@link FutureTask}.</p> * * <p>An asynchronous task is defined by a computation that runs on a background thread and * whose result is published on the UI thread. An asynchronous task is defined by 3 generic * types, called <code>Params</code>, <code>Progress</code> and <code>Result</code>, * and 4 steps, called <code>onPreExecute</code>, <code>doInBackground</code>, * <code>onProgressUpdate</code> and <code>onPostExecute</code>.</p>

AsyncTask很适合也很简单在UI线程中使用,可以在后台线程中处理任务然后把结果推送到UI线程,不需要处理线程或者handlers。

AsyncTask是设计用于帮助线程和handler的,不是通常的线程框架,它理论上用于很短的操作(几秒内),如果想保持线程很长一段时间,

强烈推荐使用java.util.concurrent包中的APIS,比如Executor、ThreadPoolExecutor、FutureTask

异步任务放在后台线程中处理,然后把结果推送给UI线程,


AsyncTask定义了3个泛型参数:Params、Progress、Result,

定义了4个步骤:onPreExecute、doInBackground、onProgressUpdate、onPostExecute。



说白了AsyncTask是官方定义的一个简单处于短时间异步操作的工具类,长时间异步操作还是不适合用的。


看下怎么使用的


    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        AsyncTask<Integer, Integer, Integer> task = new AsyncTask<Integer, Integer, Integer>() {            @Override            protected void onPreExecute() {                super.onPreExecute();                Log.d(TAG, "onPreExecute");            }            @Override            protected Integer doInBackground(Integer... objects) {                Log.d(TAG, "doInBackground");                return objects[0];            }            @Override            protected void onProgressUpdate(Integer... values) {                super.onProgressUpdate(values);                Log.d(TAG, "onProgressUpdate");            }            @Override            protected void onPostExecute(Integer o) {                super.onPostExecute(o);                Log.d(TAG, "onPostExecute" + "  " + o);            }            @Override            protected void onCancelled() {                super.onCancelled();                Log.d(TAG, "onCancelled");            }        };        task.execute(1);    }

这里实现了一个AsyncTask的例子,常用的几个方法都写出来了,直接执行看下打印结果

12-08 07:11:22.924 3799-3799/? D/MainActivity: onPreExecute
12-08 07:11:22.925 3799-3839/? D/MainActivity: doInBackground
12-08 07:11:22.948 3799-3799/? D/MainActivity: onPostExecute  1


先来简单介绍下这几个方法


onPreExecute()            看名字也知道这个是前置操作,UI线程中执行

doInBackground()        后台中执行任务,线程中执行

onProgressUpdate()    后台任务执行过程中的操作,比如显示进度条,UI线程中执行

onPostExecute()           后台任务完成后执行,UI线程中执行

onCancelled()               任务取消,UI线程中执行


它们也是按步骤执行的,onPreExecute()→doInBackground() →onProgressUpdate()→onPostExecute(),onCancelled()不是步骤之一,只是一个任务取消的回调,整个任务只能执行一次。


现在开始一一击破吧,从源码分析到底它们都做了什么


    /**     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.     */    public AsyncTask() {        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;            }        };        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);                }            }        };    }    private void postResultIfNotInvoked(Result result) {        final boolean wasTaskInvoked = mTaskInvoked.get();        if (!wasTaskInvoked) {            postResult(result);        }    }

看下AsyncTask构造函数,会看到new了WorkerRunnable对象和FutureTask对象,看下

    private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {        Params[] mParams;    }


WorkerRunnable是一个实现了Callable的抽象类,Callable跟Runnable差不多,只是一个无返回值一个有返回值,FutureTask用于后台任务执行完毕或者取消后台任务后的监听。

WorkerRunnable中call()里面看到doInBackground()了吧,哈哈,就是前面说到的执行后台任务的方法,肯定要有个地方开启这个异步线程才能执行doInBackground(),那么接下来看下开启的方法吧。


execute()

    /**     * Executes the task with the specified parameters. The task returns     * itself (this) so that the caller can keep a reference to it.     *      * <p>Note: this function schedules the task on a queue for a single background     * thread or pool of threads depending on the platform version.  When first     * introduced, AsyncTasks were executed serially on a single background thread.     * Starting with {@link android.os.Build.VERSION_CODES#DONUT}, this was changed     * to a pool of threads allowing multiple tasks to operate in parallel. Starting     * {@link android.os.Build.VERSION_CODES#HONEYCOMB}, tasks are back to being     * executed on a single thread to avoid common application errors caused     * by parallel execution.  If you truly want parallel execution, you can use     * the {@link #executeOnExecutor} version of this method     * with {@link #THREAD_POOL_EXECUTOR}; however, see commentary there for warnings     * on its use.     *     * <p>This method must be invoked on the UI thread.     *     * @param params The parameters of the task.     *     * @return This instance of AsyncTask.     *     * @throws IllegalStateException If {@link #getStatus()} returns either     *         {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.     *     * @see #executeOnExecutor(java.util.concurrent.Executor, Object[])     * @see #execute(Runnable)     */    @MainThread    public final AsyncTask<Params, Progress, Result> execute(Params... params) {        return executeOnExecutor(sDefaultExecutor, params);    }

    /**     * Executes the task with the specified parameters. The task returns     * itself (this) so that the caller can keep a reference to it.     *      * <p>This method is typically used with {@link #THREAD_POOL_EXECUTOR} to     * allow multiple tasks to run in parallel on a pool of threads managed by     * AsyncTask, however you can also use your own {@link Executor} for custom     * behavior.     *      * <p><em>Warning:</em> Allowing multiple tasks to run in parallel from     * a thread pool is generally <em>not</em> what one wants, because the order     * of their operation is not defined.  For example, if these tasks are used     * to modify any state in common (such as writing a file due to a button click),     * there are no guarantees on the order of the modifications.     * Without careful work it is possible in rare cases for the newer version     * of the data to be over-written by an older one, leading to obscure data     * loss and stability issues.  Such changes are best     * executed in serial; to guarantee such work is serialized regardless of     * platform version you can use this function with {@link #SERIAL_EXECUTOR}.     *     * <p>This method must be invoked on the UI thread.     *     * @param exec The executor to use.  {@link #THREAD_POOL_EXECUTOR} is available as a     *              convenient process-wide thread pool for tasks that are loosely coupled.     * @param params The parameters of the task.     *     * @return This instance of AsyncTask.     *     * @throws IllegalStateException If {@link #getStatus()} returns either     *         {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.     *     * @see #execute(Object[])     */    @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;    }

这里就是整个任务的开启入口了,看到了sDefaultExecutor了吧,来看下它是啥

    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
    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);            }        }    }

sDefaultExecutor其实是一个Executor实例,里面定义了一个成员变量ArrayDeque ,通过前面的executeOnExecutor()可以知道一来就判断任务执行的状态,枚举类型Status有3个状态,通过成员量知道创建AsyncTask实例时就会初始化状态为PENDING

    private volatile Status mStatus = Status.PENDING;

    /**     * Indicates the current status of the task. Each status will be set only once     * during the lifetime of a task.     */    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,    }

执行任务中,如果状态不为PENDING,就抛出相应异常,否则改变状态为RUNNING,接下来看到onPreExecute()了吧,对,这个就是最开始执行的步骤,在主线程中的,接下来执行初始化时定义的FutureTask实例。


接下来会怎么执行呢?


再次看到这段代码

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


Executor的实例开始执行execute()方法,通过一个双端队列存取传过来的FutureTask实例,然后调用scheduleNext(),从这里开始用了一个线程池去执行FutureTask实例,看下这线程池的定义


    /**     * An {@link Executor} that can be used to execute tasks in parallel.     */    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;    }

静态块,会在AsyncTask构造的时候调用,生成了这么一个线程池,还是静态的,一个进程里面无论有多少AsyncTask的实例,这个线程池都只有这么一个,避免内存的过多开销,如果每创建一个AsyncTask都创建一个线程池肯定是非常浪费性能的。

接着就会去执行WorkerRunnable中的call()方法,线程中执行,不管抛不抛异常,doInBackground()会返回一个值Result,然后通过

postResult(result)发送到UI线程,无论任务执行完毕还是取消最后都会执行Futrue中的done(),里面有个postResultIfNotInvoked(),只有call()未调用前取消了任务才会有效,然后去调用postResult()


    private void postResultIfNotInvoked(Result result) {        final boolean wasTaskInvoked = mTaskInvoked.get();        if (!wasTaskInvoked) {            postResult(result);        }    }


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

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

接受到MESSAGE_POST_RESULT消息,调用了finish(),先看下InternalHandler,说白了就是自定义的一个用于更新UI操作的Handler

    /**     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.     *     * @hide     */    public AsyncTask(@Nullable Looper callbackLooper) {        mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()            ? getMainHandler()            : new Handler(callbackLooper);

以开始构造AsyncTask的时候就做了判断,这里会获取getMainHandler()


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

可能会说要是传一个子线程的Looper进来,那么不就不会了吗?

AsyncTask是一个抽象类,是不能new的,所以它的带参构造方法都不能直接用,但是构造子类的时候会默认执行父类无参的构造方法,所以传入的null,如果为null,就会默认获取主线程的Handler

    /**     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.     */    public AsyncTask() {        this((Looper) null);    }    /**     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.     *     * @hide     */    public AsyncTask(@Nullable Handler handler) {        this(handler != null ? handler.getLooper() : null);    }    /**     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.     *     * @hide     */    public AsyncTask(@Nullable Looper callbackLooper) {        mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()            ? getMainHandler()            : new Handler(callbackLooper);


回到刚才的finish()

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


可以看到如果任务中途被取消了就调用onCancelled(),否则调用onPostExecute(),这个就是步骤4了,后台执行完毕任务通知UI线程做相关处理,这个result就是后台执行完毕返回的值,然后状态改为FINISHED

到这里一个任务就完成了,已经看到3个步骤了,那么会问,还有一个步骤onProgressUpdate()呢?客观莫急


    /**     * 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 not be called if the task has been     * canceled.     *     * @param values The progress values to update the UI with.     *     * @see #onProgressUpdate     * @see #doInBackground     */    @WorkerThread    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 {        public InternalHandler(Looper looper) {            super(looper);        }        @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;            }        }    }


其实呢这个方法并不是后台给我处理的,是需要我们自己去执行publishProgress(),才会通过handler去调用onProgressUpdate(),

publishProgress()往往在doInBackground()中调用的,比如加载进度,有点进度就发送消息调用onProgressUpdate()刷新UI。


还有一个主动取消任务的方法cancel(),当调用了这个方法,异步执行的任务会被打断抛出异常,调用onCancelled()

    /**     * <p>Attempts to cancel execution of this task.  This attempt will     * fail if the task has already completed, already been cancelled,     * or could not be cancelled for some other reason. If successful,     * and this task has not started when <tt>cancel</tt> is called,     * this task should never run. If the task has already started,     * then the <tt>mayInterruptIfRunning</tt> parameter determines     * whether the thread executing this task should be interrupted in     * an attempt to stop the task.</p>     *      * <p>Calling this method will result in {@link #onCancelled(Object)} being     * invoked on the UI thread after {@link #doInBackground(Object[])}     * returns. Calling this method guarantees that {@link #onPostExecute(Object)}     * is never invoked. After invoking this method, you should check the     * value returned by {@link #isCancelled()} periodically from     * {@link #doInBackground(Object[])} to finish the task as early as     * possible.</p>     *     * @param mayInterruptIfRunning <tt>true</tt> if the thread executing this     *        task should be interrupted; otherwise, in-progress tasks are allowed     *        to complete.     *     * @return <tt>false</tt> if the task could not be cancelled,     *         typically because it has already completed normally;     *         <tt>true</tt> otherwise     *     * @see #isCancelled()     * @see #onCancelled(Object)     */    public final boolean cancel(boolean mayInterruptIfRunning) {        mCancelled.set(true);        return mFuture.cancel(mayInterruptIfRunning);    }



好了,到这里基本都解析完毕了,不过还有很多知识点没有深入,这里就不深入了,又可以愉快的玩耍了大笑










原创粉丝点击