关闭

[Android] AsyncTask 的学习

274人阅读 评论(0) 收藏 举报
分类:

关于AsyncTask的几点学习
1. AsyncTask是一个抽象类。
2. AsyncTask实际上是Thread和Handler的帮组类。并且用在短时操作(一般几秒以内)会比较理想。

AsyncTask使用泛型定义一些参数类型,分别是 Params,Progress,Result;
Params, 发送的任务参数类型.
Progress, 后台计算时进度单位的类型.
Result,后台计算的返回结果类型.

AsyncTask定义了4个方法,分别是 onPreExecute、doInBackground、onProgressUpdate 和 onPostExecute.

onPreExecute
在UI线程中执行,而且在任务开始前。
这个步骤一般使用在设置任务的一些参数等,举个例子说明,比如在UI界面显示一个进度条;
doInBackground
在后台线程中调用,当onPreExecute完成后立即被执行。这一方法被用于在后台执行一些耗时的操作。异步任务的参数也将传递过来,计算的结果也会从这一方法传递回去,我们也可以在这一方法中使用publishProgress 方法去更新进度。
onProgressUpdate
在publishProgress方法后执行,这个方法执行在UI线程中,执行的时间是不确定的。
这个方法可以显示后台计算的进度,举个例子:它可以用进度条或者文字来显示进度。
onPostExecute
在UI线程上调用后台计算完成之后。后台计算的结果作为一个参数传递给这个方法。

另外,还需要提及的一个方法是 取消任务。
cancel(boolean)
调用cancel这个方法,后台计算的任务可以随时取消,调用这个方法,后续会通过isCancelled()方法返回取消的结果。
注意事项
使用AsyncTask的一些注意事项:
(1) AsyncTask 类必须在UI线程中被加载,实例需要在UI线程中被创建,在UI线程中被执行;
(2) 不要试图去手动调用onPreExecute、onPostExecute、doInBackground、onProgressUpdate方法;
(3) 一个任务只能执行一次,多次执行会抛出异常;
内存可观察性
AsyncTask 保证所有的回调都是同步的,是线程安全的。
执行顺序
最初被引进时,异步任务执行在一系列的后台线程中。从DONUT开始他被线程池所替代,这让它允许多任务并行。从HONEYCOMB开始,为了避免并行操作引起的公共应用错误,让任务在一个单线程中被执行,
如果你真的希望并行操作,你可以调用 THREAD_POOL_EXECUTOR 的 executeOnExecutor方法。

public abstract class AsyncTask<Params, Progress, Result> {
    protected void onPreExecute() {
    }

    protected void onProgressUpdate(Progress... values) {
    }

    protected void onPostExecute(Result result) {
    }

    protected abstract Result doInBackground(Params... params);

    public final boolean isCancelled() {
        return mCancelled.get();
    }

    protected void onCancelled() {
    }

    protected void onCancelled(Result result) {
        onCancelled();
    }   
}

以下是 AsyncTask 的源码

package android.os;

import java.util.ArrayDeque;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

public abstract class AsyncTask<Params, Progress, Result> {
    private static final String LOG_TAG = "AsyncTask";

    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();  // 4
    private static final int CORE_POOL_SIZE = CPU_COUNT + 1;                          // 5
    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;                   // 9 
    private static final int KEEP_ALIVE = 1;

    // ThreadFactory 工厂类 方便创建线程对象
    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());
        }
    };

    // 一个存储 Runnable 容量为 128 的 LinkedBlockingQueue 队列
    private static final BlockingQueue<Runnable> sPoolWorkQueue =
            new LinkedBlockingQueue<Runnable>(128);

    /**
     * 一个可以并行执行任务的 Executor 对象 THREAD_POOL_EXECUTOR
     */
    public static final Executor THREAD_POOL_EXECUTOR
            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

    /**
     * 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 final int MESSAGE_POST_RESULT = 0x1;
    private static final int MESSAGE_POST_PROGRESS = 0x2;

    // 默认的 Executor 对象 sDefaultExecutor 串行执行
    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
    // 一个内部的 handler InternalHandler
    private static InternalHandler sHandler;

    // WorkRunnable 一个 Callable 对象
    private final WorkerRunnable<Params, Result> mWorker;
    // 可取消的异步任务
    private final FutureTask<Result> mFuture;

    // 当前的状态,初始化为 pending 状态
    private volatile Status mStatus = Status.PENDING;

    private final AtomicBoolean mCancelled = new AtomicBoolean();
    private final AtomicBoolean mTaskInvoked = new AtomicBoolean();

    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 enum Status {
        /**
         * 表明任务尚未被执行
         */
        PENDING,
        /**
         * 表明任务正在运行
         */
        RUNNING,
        /**
         * 表明 AsyncTask onPostExecute 已经执行结束
         */
        FINISHED,
    }

    // 单例创建 sHandler ?? 类单例 还是对象单例 这个锁
    private static Handler getHandler() {
        synchronized (AsyncTask.class) {
            if (sHandler == null) {
                sHandler = new InternalHandler();
            }
            return sHandler;
        }
    }

    /** @hide */
    public static void setDefaultExecutor(Executor exec) {
        sDefaultExecutor = exec;
    }

    /**
     * 创建一个新的异步任务,这个构造器必须在UI线程中执行
     */
    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);
                }
            }
        };
    }

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

    /**
     * Returns the current status of this task.
     *
     * @return The current status.
     */
    public final Status getStatus() {
        return mStatus;
    }

    /**
     * 重写这个方法用来执行一个后台计算线程。
     * 这些特殊的参数是这个任务的调用者传递给执行者的
     * 这个方法可以调用 publishProgress 去更新 UI 线程
     *
     * @param params The parameters of the task.
     *
     * @return A result, defined by the subclass of this task.
     *
     */
    protected abstract Result doInBackground(Params... params);

    /**
     * 在 UI 线程中被执行,在 doInBackground 前执行~
     *
     * @see #onPostExecute
     * @see #doInBackground
     */
    protected void onPreExecute() {
    }

    /**
     * 在 doInBackground 之后被执行,运行在 UI 线程中,
     * 特殊的 result 值是 doInBackground 中返回的,
     * 如果 task 被取消了,这个方法将不会被执行~
     *
     * @param result The result of the operation computed by {@link #doInBackground}.
     *
     */
    @SuppressWarnings({"UnusedDeclaration"})
    protected void onPostExecute(Result result) {
    }

    /**
     * 运行在 UI 线程中,在 publishProgress 之后执行.
     * 制定的值是传递给 publishProgress 的值.
     *
     * @param values The values indicating progress.
     *
     */
    @SuppressWarnings({"UnusedDeclaration"})
    protected void onProgressUpdate(Progress... values) {
    }

    /**
     * 在 UI 线程中被执行,在 cancle(boolean) 执行之后
     * 并且 doInBackground(Object[]) 执行结束.
     * 默认的实现知识简单的触发 onCancelled() 而忽略结果,
     * 如果你写你自己的实现,不要调用 super.onCancelled(result)
     *
     * @param result The result, if any, computed in
     *               {@link #doInBackground(Object[])}, can be null
     * 
     */
    @SuppressWarnings({"UnusedParameters"})
    protected void onCancelled(Result result) {
        onCancelled();
    }    

    /**
     * 应用程序最好可以覆盖 onCancelled(Object) 方法,
     * 这个方法在默认的 onCancelled(Object)中被实现.
     * 
     * 运行在 UI 线程中,在 cancel(boolean) 
     * 执行之后并且 doInBackground(Object[]) 执行结束
     */
    protected void onCancelled() {
    }

    /**
     * 如果任务在正常结束之前被取消则返回 true,
     * 如果你正在调用 cancel(boolean),
     * 这个函数返回值将需要从 doInBackground(Object[]) 
     * 到结束这个任务之间的时间里定期检查.
     *
     * @return <tt>true</tt> if task was cancelled before it completed
     *
     */
    public final boolean isCancelled() {
        return mCancelled.get();
    }

    /**
     * 试图去取消这个任务的执行,如果任务已经完成了或者已经
     * 被取消了或者其他原因不能被取消的,这次尝试就会失败;
     * 
     * 如果成功,而且这个任务还没有开始就别取消了,
     * 这个任务应该永远都不会运行;如果任务已经开始了,
     * 然后 mayInterruptIfRunning 参数决定是否应该中断执行的任务。 
     *  
     * 执行这个方法将导致 onCancelled(Object) 在 UI 线程中被触发,
     * 在 doInBackground(Object[]) 返回后,执行这个方法保证 
     * onPostExecute(Object) 永远不会被执行.
     * 
     * 在触发这个方法之后,你应该在 doInBackground(Object[])
     * 到结束这个 Task 的时间内定期地检查 isCancelled() 返回的值.
     *
     * @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);
    }

    /**
     * 如果有需要的话会等待计算完成,然后获取它的结果.
     *
     *
     * @throws CancellationException If the computation was cancelled.
     * @throws ExecutionException If the computation threw an exception.
     * @throws InterruptedException If the current thread was interrupted
     *         while waiting.
     */
    public final Result get() throws InterruptedException, ExecutionException {
        return mFuture.get();
    }

    /**
     * 如果有需要的话会等待计算完成,给定最多等待的时间,然后获取它的结果.
     *
     * @return The computed result.
     *
     * @throws CancellationException If the computation was cancelled.
     * @throws ExecutionException If the computation threw an exception.
     * @throws InterruptedException If the current thread was interrupted
     *         while waiting.
     * @throws TimeoutException If the wait timed out.
     */
    public final Result get(long timeout, TimeUnit unit) throws InterruptedException,
            ExecutionException, TimeoutException {
        return mFuture.get(timeout, unit);
    }

    /**
     * 使用指定的参数去执行任务,这个任务返回它本身,
     * 以便于调用者可以保持它的一个引用.
     * 
     * 注意:这个方法在执行任务的方式上要依赖于平台的版本,
     * 刚开始被引入时,异步任务串行执行在一个单独的后台线程中
     * 从 DONUT 开始,多任务并行执行在一个线程池中,HONEYCOMB 开始,任务又改为串行执行在一个单独的线程中,这样做是为了
     * 避免一些并行的异常. 如果你真的希望做并行计算,你可以使用 executeOnExecutor 的版本和 THREAD_POOL_EXECUTOR.
     * 注意看这个方法的评论警告
     * 
     * 这个方法只能在 UI 线程上调用.
     *
     * @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}.
     *
     */
    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }

    /**
     * 使用指定的参数去执行任务,这个任务返回它本身,以便于调用者可以保持它的一个引用.
     * 
     * 这个方法通常和 THREAD_POOL_EXECUTOR 一起使用,这样就允许了众多任务在一个 AsyncTask 管理的线程池中并行.
     * 当然,你依旧可以使用自定义行为的 Executor.
     * 
     * 警告:允许多任务在一个线程池中并行计算通常不是我们所想要的,因为执行的顺序是不确定的.
     * 举个例子来讲,如果这些任务是用来修改一些公共的状态的(必须单击一个按钮之后去写文件),这就不能保证修改的顺序.
     * 如果没有认真检查,在少数情况下可能出现,最新的版本被以前的老版本所复写的情况,这就导致了数据的丢失和稳定下差的情况.
     * 这种变化最好是串行执行,无论平台版本如何,都可以保证这些工作被序列化。
     *
     * 这个方法必须在 UI 线程中被执行.
     *
     * @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[])
     */
    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;
    }

    /**
     * execute(Object...) 的简单版本,去使用一个简单的 Runnable 对象.
     *
     * @see #execute(Object[])
     * @see #executeOnExecutor(java.util.concurrent.Executor, Object[])
     */
    public static void execute(Runnable runnable) {
        sDefaultExecutor.execute(runnable);
    }

    /**
     * 这个方法可以在 doInBackground 中被触发,在后台计算仍然运行的情况下在 UI 线程中更新进度
     * 每次调用这个方法都将触发 UI 线程中的 onProgressUpdate 方法
     *
     * {@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
     */
    protected final void publishProgress(Progress... values) {
        if (!isCancelled()) {
            getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                    new AsyncTaskResult<Progress>(this, values)).sendToTarget();
        }
    }

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

    private static class InternalHandler extends Handler {
        public InternalHandler() {
            super(Looper.getMainLooper());
        }

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

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

    @SuppressWarnings({"RawUseOfParameterizedType"})
    private static class AsyncTaskResult<Data> {
        final AsyncTask mTask;
        final Data[] mData;

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

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:40907次
    • 积分:1095
    • 等级:
    • 排名:千里之外
    • 原创:66篇
    • 转载:17篇
    • 译文:1篇
    • 评论:3条
    最新评论