AsyncTask源码详解

1,简介:

AsyncTask允许正确且容易地使用UI线程。该类允许您在UI线程上执行后台操作并发布结果,而无需操作thread或者handler。

AsyncTask被设计成一个围绕thread和handler程序的帮助类,而不是一个通用的线程框架。异步任务理想情况下应该用于短操作(最多几秒钟)。如果您需要让线程长时间运行,强烈建议您使用 java.util.concurrent提供的各种并发api,如Executor、ThreadPoolExecutor和FutureTask。

AsyncTask由在后台线程上运行的计算定义,其结果在UI线程上发布。AsyncTask由3种泛型类型(称为Params、Progress和Result)和4个步骤(称为onPreExecute、doInBackground、onProgressUpdate和onPostExecute)定义。

AsyncTask是基于 java.util.concurrent包中的ThreadPoolExecutor实现的线程池。默认是串行执行的,但也可以并行。

2,使用

2.1覆盖4个方法。

public class LoadingTask extends AsyncTask<String, Integer, Byte[]> {

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        //UI线程  准备逻辑
    }

    @Override
    protected Byte[] doInBackground(String... strings) {
        //工作线程 实现耗时逻辑

        return new Byte[0];
    }

    @Override
    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values);
        //UI线程  进度更新通知
    }

    @Override
    protected void onPostExecute(Byte[] bytes) {
        super.onPostExecute(bytes);
        //UI线程  结果
    }
}

2.2执行代码


//并发执行
new LoadingTask().executeOnExecutor(LoadingTask.THREAD_POOL_EXECUTOR,"loadingUrl");
//默认串行执行
new LoadingTask().execute("loadingUrl");

3.构造方法

3.1不带参数的构造方法调用带参数的构造方法。

new LoadingTask() 默认调用父类AsyncTask不带参数的构造方法。

/**
 *  创建一个异步任务,这个构造方法必须在UI线程中调用。
 */
public AsyncTask() {
    this((Looper) null);
}

3.2带参数的构造方法。

AsyncTask空的构造方法又调用了,带一个参数(Looper)的构造方法,并且传入了null。


/**
 *  创建一个异步任务,这个构造方法必须在UI线程中调用。
 */
public AsyncTask(@Nullable Looper callbackLooper) {
        //给mHandler赋UI线程Handler值
        mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
            ? getMainHandler()
            : new Handler(callbackLooper);
        //初始化工作任务
        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);
                Result result = null;
                try {
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    //这里调用doInBackground方法。
                    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);
                }
            }
        };
    }

3.3 WorkerRunnable抽象类的源码与解释。

    /**
     * 基于返回结果Result并可能引发异常的任务Callabe。
     * 子类实现WorkerRunnable需要实现了一个没有参数调用的方法call。
     * Callable类似于Runnable,因为它们都是为实例可能由另一个线程执行的类设计的。然而,Runnable不返回结果,也不能抛出检查过的异常。
     * Executors类包含实用程序方法,用于从其他公共表单转换为可调用类。
     *
     * @param <Params>
     * @param <Result>
     */
    private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
        /**
         * 传入doInBackground方法的参数
         */
        Params[] mParams;
    }

3.4 mFuture的定义与解释。

    /**
     * 可取消的异步计算。
     * FutureTask提供了Future的基本实现,提供了启动和取消计算、查询计算是否完成以及检索计算结果的方法。
     * 计算完成后才能检索结果;如果计算尚未完成,get方法将阻塞。一旦计算完成,就不能重新启动或取消计算(除非使用runAndReset调用计算)。
     * FutureTask可以用来包装一个可调用或可运行的对象。因为FutureTask实现了Runnable,所以FutureTask可以提交给执行程序执行。
     * 除了作为独立类使用之外,FutureTask还提供了在创建定制任务类时可能有用的受保护功能。
     */
    private final FutureTask<Result> mFuture;

4 串行执行

AsyncTask默认是串行执行的。

execute方法也是调用的executeOnExecutor方法。传入的是sDefaultExecutor

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

串行线程池的sDefaultExecutor的实现:

    /**
     * 串行执行线程池。
     */
    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

SERIAL_EXECUTOR的定义:

     /**
     * 一个{@link Executor},按串行顺序一次执行一个任务。这种序列化对于特定的流程是全局的。
     */
    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

SerialExecutor是串行执行的,这也是AsyncTask的默认行为。

    /**
     * 串行Executor,基于THREAD_POOL_EXECUTOR实现串行
     */
    private static class SerialExecutor implements Executor {
        /**
         * 串行任务的双端队列
         */
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        Runnable mActive;

        @Override
        public synchronized void execute(final Runnable r) {
            mTasks.offer(new Runnable() {
                @Override
                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);
            }
        }
    }

5 平行执行

THREAD_POOL_EXECUTOR定义与解释

    /**
     * cup个数
     */
    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    /**
     * 核心线程数
     * 我们希望在核心池中至少有2个线程,最多4个线程,希望比CPU计数少1个线程,以避免后台工作占用CPU
     */
    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;
    /**
     * alive时间 30s
     */
    private static final int KEEP_ALIVE_SECONDS = 30;
    /**
     * 根据需要创建新线程的对象。
     * 使用线程工厂可以删除对新线程的硬连接调用,
     * 使应用程序能够使用特殊的线程子类、优先级等。
     */
    private static final ThreadFactory sThreadFactory = new ThreadFactory() {
        private final AtomicInteger mCount = new AtomicInteger(1);

        @Override
        public Thread newThread(Runnable r) {
            return new Thread(r, "MyAsyncTask #" + mCount.getAndIncrement());
        }
    };
    /**
     * 任务队列,容量128个
     */
    private static final BlockingQueue<Runnable> sPoolWorkQueue =
            new LinkedBlockingQueue<Runnable>(128);

    /**
     * An {@link Executor} 并行执行的线程池.
     */
    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, new ThreadPoolExecutor.DiscardOldestPolicy());
        threadPoolExecutor.allowCoreThreadTimeOut(true);
        THREAD_POOL_EXECUTOR = threadPoolExecutor;
    }

executeOnExecutor方法。executeOnExecutor方法允许你指定任务是串行还是并行执行的Executor,

传入使用THREAD_POOL_EXECUTOR,并行执行。

传入使用SERIAL_EXECUTOR,串行执行。

执行前调用了onPreExecute方法。

    @MainThread
    public final MyAsyncTask<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;
    }

6 post结果

 mFuture = new FutureTask<Result>(mWorker) {
            /**
             * 任务结束后调用改方法
             */
            @Override
            protected void done() {
                try {
                    //调用get获取结果,并分发。
                    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);
                }
            }
        };

解释再多,不如直接看源码来的直接。从源码可以看出,task执行完以后会调用postResultIfNotInvoked(Result result),传入的结果是get方法返回的。

再看看postResultIfNotInvoked的源码

    /**
     * 分发结果
     *
     * @param result
     */
    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;
    }

可以看出,postResultIfNotInvoked方法调用了postResult方法。最终通过Handler给UI线程发送了Message,告知了Result结果。

7 onProgressUpdate方法何时触发

当后台task仍在运行时,可以从doInBackground调用publishProgress方法在UI线程上发布更新。

对这个方法的每次调用都会触发UI线程上onProgressUpdate的执行。 如果任务已被取消,则不会调用onProgressUpdate。

    @WorkerThread
    protected final void publishProgress(Progress... values) {
        if (!isCancelled()) {
            getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                    new AsyncTaskResult<Progress>(this, values)).sendToTarget();
        }
    }

很简单吧。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值