AsyncTask的使用及其原理

概述

Android 已封装好的轻量级异步类。内置一个线程池用于异步任务,另一个线程池用于排队(实际不是线程池)。一个默认绑定mainLooper的Handler用于UI线程。

使用

  • public abstract class AsyncTask Params 传参的类型,Progress 进度的类型,Result 返回结果的类型
  • execute(Params... params):执行一个异步任务,需要我们在代码中调用此方法,触发异步任务的执行。UI线程调用。
  • onPreExecute():在execute(Params... params)被调用后立即执行,一般用来在执行后台任务前对UI做一些准备工作。
  • doInBackground(Params... params) 关键方法,用于执行较为费时的操作,在onPreExecute()完成后立即执行,此方法将接收输入参数和返回计算结果。doInBackground方法接收的参数就是execute()中传入的参数:另外在执行过程中可以调用publishProgress(Progress... values)来更新进度信息。
  • onProgressUpdate(Progress... values),如果调用publishProgress(Progress... values)时,此方法被执行,直接将进度信息更新到UI组件上。否则不执行
  • onPostExecute(Result result),当后台操作结束时,此方法将会被调用,计算结果(就是doInBackground方法返回的结果)将做为参数传递到此方法中,直接将结果显示到UI组件上。
  • cancel(boolean)方法,可以取消任务。这个方法会产生的影响是:之后调用的iscancelled()会返回true。

源码分析

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

THREAD_POOL_EXECUTOR 是真正用于异步任务的线程池。可以看到它是静态的,也就是每次new AsyncTask()都是用的同一个线程池。

public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static class SerialExecutor implements Executor {
        final ArrayDeque mTasks = new ArrayDeque();//ArrayDeque依赖于可变数组来实现的双端队列,可根据需求自动进行扩容。
        Runnable mActive;//当前执行的任务

        public synchronized void execute(final Runnable r) {
            mTasks.offer(new Runnable() {//offer向队列中插入一个元素,并返回true,如果队列已满,返回false(add在满时报错)
                public void run() {
                    try {
                        r.run();
                    } finally {
                        scheduleNext();
                    }
                }
            });
            if (mActive == null) {
                scheduleNext();
            }
        }

        protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {//poll取出队列头部的元素,并从队列中移除
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }

SERIAL_EXECUTOR 是实现了Executor 接口,但内部操作是把Runnable 任务放入一个ArrayDeque(双端队列)。并且每执行完一个取出下一个任务执行。其实它不是线程池。
AsyncTask.execute()默认会调用到这个对象执行,它会一个个的取出任务再用真正的线程池THREAD_POOL_EXECUTOR执行,由此可见,用一个AsyncTask对象执行多个任务会是串行执行的。那么如何让它并行执行呢?改为调用AsyncTask.executeOnExecuter(AsyncTask.THREAD_POOL_EXECUTOR,"")就可以了。

 public AsyncTask(@Nullable Looper callbackLooper) {// 默认构造方法会走到这里
        mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
            ? getMainHandler()// 一般是绑定mainLooper的内置的Handler类
            : new Handler(callbackLooper);// 特殊情况

        mWorker = new WorkerRunnable() { // 继承callable的类
            public Result call() throws Exception {
                mTaskInvoked.set(true);// 调用标识,FutureTask的done方法里调postResultIfNotInvoked会判断
                Result result = null;
                try {
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);// 设置线程的优先级
                    //noinspection unchecked
                    result = doInBackground(mParams);//这里调关键方法doInBackground,执行耗时任务,并获取结果
                    Binder.flushPendingCommands(); //将进程中未执行的命令,一并送往CPU处理
                } catch (Throwable tr) {
                    mCancelled.set(true);//如果运行异常,设置取消的标志
                    throw tr;
                } finally {
                    postResult(result);//发送结果
                }
                return result;
            }
        };
        //一个包装任务的包装类,与callable结合使用
        mFuture = new FutureTask(mWorker) {
            @Override
            protected void done() {
                try {//在执行完任务做一道检查,将没被调用的Result也一并发出.这个方法根据上面的mTaskInvoked判断
                    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);//如果发生异常,则将结果滞null发出.
                }
            }
        };
    }

callable与runnable的区别是,他的call方法有返回值。所以AsyncTask没有用runnable而是用的

你可能感兴趣的:(AsyncTask的使用及其原理)