码迷,mamicode.com
首页 > 移动开发 > 详细

Android异步处理框架AsyncTask源码解析

时间:2016-05-03 18:44:30      阅读:273      评论:0      收藏:0      [点我收藏+]

标签:

一.概述

在Android开发中,我们进行异步处理一般会采用两种方式:
1.Thread +Handler
通常我们在Thread里面发送消息,然后在Handler的handleMessage方法里面去处理对应的任务,因为Android是不允许UI线程去更新UI的,这个时候我们可以采取这种方式
2.AsyncTask
AsyncTask是Android为我们封装的一个轻量级的异步处理框架,其实底层也是用了类似Thread+Handler的方式。对外提供了一些方法,我们实现这些方法就可以很方便的进行异步处理了。

对比

既然两种方式都可以实现异步处理任务,那么有什么区别呢?该使用哪个呢?

1.AsyncTask实现的原理和适用的优缺点
AsyncTask,是android提供的轻量级的异步类,可以直接继承AsyncTask,在类中实现异步操作,并提供接口反馈当前异步执行的程度(可以通过接口实现UI进度更新),最后反馈执行的结果给UI主线程.
使用的优点:
简单,快捷
过程可控
使用的缺点:
在使用多个异步操作和并需要进行Ui变更时,就变得复杂起来.
2.Handler异步实现的原理和适用的优缺点
在Handler 异步实现时,涉及到 Handler, Looper, Message,Thread四个对象,实现异步的流程是主线程启动Thread(子线程)运行并生成Message-Looper获取Message并 传递给HandlerHandler逐个获取Looper中的Message,并进行UI变更。
使用的优点:
结构清晰,功能定义明确
对于多个后台任务时,简单,清晰
使用的缺点:
在单个后台异步处理时,显得代码过多,结构过于复杂(相对性)
综上所述:
数据简单使用AsyncTask:实现代码简单,数据量多且复杂使用handler+thread :相比较
AsyncTask来说能更好的利用系统资源且高效 .AsyncTask其实是Android给开发者提供的
一个简单轻量级的多线程类,通过它我们可以很容易新建一个线程做一些耗时的操作,并在
这个过程中更 新UI。之所以说它轻量级,是因为缺少了直接使用Thread的灵活性。如果是
很复杂的操作,还是建议通过Thread来操作,然后通过 Broadcast的方式来更新UI。

好了,看了两种方式的区别,我们进入今天的重点,AsyncTask源码的分析。

二.源码分析

我们平时会这样使用AsyncTask,
1.创建一个类继承AyncTask(因为AsyncTask是抽象的)

 class MyTask extends AsyncTask<Integer,String,String>{
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }
        @Override
        protected String doInBackground(Integer[] params) {
            return null;
        }

        @Override
        protected void onPostExecute(String s) {
            super.onPostExecute(s);
        }
    }

这里讲解两个地方:
(1)参数
我们看到AsyncTask有三个泛型,Params,Progress,Result,这里分别为Integer,String,String,每个泛型代表的意思如下
Params:异步任务执行需要传入的参数类型
Progress:异步任务执行过程中返回进度值的类型
Result:异步任务执行结束后返回结果的类型
(2)方法
这里我们重写了三个最常用的方法
onPreExecute:异步任务开始之前做一些初始化的动作,比如初始化进度条,AsyncTask实例创建在哪个线程,这个方法执行在哪个线程
doInBackground:执行后台任务的方法,运行在子线程
onPostExecute:异步任务结束后调用的方法,运行在主线程,通常用来处理结果。

2.执行任务
调用如下方法使异步任务开始执行

//创建AsyncTask对象,调用execute方法
new MyTask().execute();

源码如下

public abstract class AsyncTask<Params, Progress, Result> {
    private static final String LOG_TAG = "AsyncTask";
    //获得当前CPU的核心数
    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    //当前线程池容量 = CPU核心数+1
    private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
   //最大线程池容量 = CPU核心数*2+1
    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
    //当前线程数量大于核心线程数量时,空闲线程在执行任务前等待的最大时间,超过此时间如果还没有任务则会被终止
    private static final int KEEP_ALIVE = 1;
    //创建新线程需要的线程工厂,需要作为参数传递到ThreadPoolExecutor的构造函数中
    private static final ThreadFactory sThreadFactory = new ThreadFactory() {
        private final AtomicInteger mCount = new AtomicInteger(1);

        public Thread newThread(Runnable r) {
        //使用Runnable对象创建线程对象并指定名称
            return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());//AsyncTask #1
        }
    };
    //用来保存任务的工作队列,需要作为参数传递到ThreadPoolExecutor的构造函数中,此处采用阻塞队列,遵循FIFO,容量为128,也就是说最多存储128个任务
    private static final BlockingQueue<Runnable> sPoolWorkQueue =
            new LinkedBlockingQueue<Runnable>(128);
    //根据上面的参数创建线程执行器
    public static final Executor THREAD_POOL_EXECUTOR
            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

     //顺序执行任务的Executor
    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
    //发送结果的消息
    private static final int MESSAGE_POST_RESULT = 0x1;
    //发送进度的消息
    private static final int MESSAGE_POST_PROGRESS = 0x2;
    //默认使用顺序执行器
    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
    //用来发送消息的InternalHandler
    private static InternalHandler sHandler;

    private final WorkerRunnable<Params, Result> mWorker;
    private final FutureTask<Result> mFuture;
    //默认挂起状态,等待任务执行
    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,//正在运行
        FINISHED,//执行结束
    }
    //获得InternalHandler对象
    private static Handler getHandler() {
        synchronized (AsyncTask.class) {
            if (sHandler == null) {
                sHandler = new InternalHandler();
            }
            return sHandler;
        }
    }

    /** 隐藏方法*/
    public static void setDefaultExecutor(Executor exec) {
        sDefaultExecutor = exec;
    }

    /**
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     */
    public AsyncTask() {
    //创建WorkerRunnable对象,继承自Callable,重写call方法
        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);

                //设置线程优先级Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //调用doInBackground,传入我们的输入参数
                Result result = doInBackground(mParams);
                Binder.flushPendingCommands();
                //调用postResult方法,传入doInBackground的结果
                return postResult(result);
            }
        };

        mFuture = new FutureTask<Result>(mWorker) {
            @Override
            //任务执行完毕调用此方法
            protected void done() {
                try {
                //如果没有传递任务则进行传递,get方法为获取FutureTask执行完毕的结果
                    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);
        }
    }

    .........

接下来我们看看比较重要的一个方法

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

这个方法是干啥的呢?将doInBackground处理的结果封装成一个AsyncTaskResult对象发送给自定义的Handle对象进行处理,我们可以看到这里有一个getHandler方法

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

采用了同步锁的方法来获取InternalHandler对象,这个Handler对象就是用来处理消息的,我们待会分析,获得Handler对象后,我们发送了一个msg.obj为如下的消息

new AsyncTaskResult<Result>(this, result)

我们去看看这个类

  private static class AsyncTaskResult<Data> {
        final AsyncTask mTask;
        final Data[] mData;

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

这个类很简单,有两个成员变量,代表当前任务的AsyncTask对象,这里为this,然后就是数据Data,这里我们传递过来的是doInBackground的处理结果。既然消息发送了,我们看看是如何处理的吧

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

上面先获取到了发送过来的消息,然后根据消息的类型进行了判断,进行了不同的处理,如果是投递结果的消息,执行下面的操作

 result.mTask.finish(result.mData[0]);

result.mTask就是当前的任务,然后调用了finish方法,我们去看看

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

很简单,首先判断当前任务是否取消了,如果取消了,就调用onCancelled方法,定义如下

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

当任务取消的时候会回调onCancelled方法,所以如果我们想要在任务取消的时候做一些操作,可以重写这个方法。

如果没有取消,则执行onPostExecute方法,传入我们的结果,最后将当前任务状态设置为完成,这里调用了onPostExecute方法,

至此,我们已经看到了doInbackground和onPostExecute方法的调用之处,那么还剩下一个onPreExcute方法怎么没看到啊?因为我们到目前为止只分析了创建任务实例这个过程所发生的事,任务还没执行执行呢。

任务执行

执行任务我们会调用execute方法,如果必要的话会传入参数

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

这里又调用了executeOnExecutor方法,传入了sDefaultExecutor和我们的参数,大家还记得sDefaultExecutor是什么吗?懒得向上找了,再给大家贴出来吧

 public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
  private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

就是串行执行器,我们去看看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;
    }

首先判断当前状态,前提是不是挂起状态,如果正在执行或者已经执行完毕,我们再次调用execute方法就会抛出异常,接下来将当前状态标记为正在执行,然后调用onPreExecute方法,这里我们终于看到onPreExecute方法被调用了,然后将我们执行任务时传入的参数赋值给mWorker的mParams,这个mWorker是啥,之前说过了,

private final WorkerRunnable<Params, Result> mWorker;

最后调用sDefaultExecutor 的execute执行任务,并且传入我们的FutureTask对象。至此,整个过程就完了。

接下来讲一些细节性的东西,可能大家也发现有些地方还没有分析
1.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);
            }
        }
    }

首先创建了一个ArrayDeque对象,用来接收我们的消息,然后调用了此对象的offer方法,再里面调用了execute参数中Runnable对象的run方法,那么这个Runnable对象是啥啊,如果你仔细阅读了上面的内容,就会发现这个Runnable对象就是FutureTask,为什么FutureTask能转换为Runnable呢,

public class FutureTask<V> implements RunnableFuture<V> 

public interface RunnableFuture extends Runnable, Future {

明白了吧,废话我就不说了,
那么我们就去看看FutureTask的run方法

 public void run() {
        if (state != NEW ||
            !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
            return;
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    result = c.call();
                    ran = true;
                    .....

只讲重点,这里将一个callable对象赋值给了一个新的对象,然后调用了call方法,我们看看这个callable对象是在哪里赋值的

 public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }

是在FutureTask构造方法里面复制的,到这大家是不是想起什么了,是的,我们再AsyncTask中创建锅Callable的实现类WorkerRunnable并且将其传给了FutureTask的构造函数,所以,当我们最终调用sDefaultExecutor 的execute方法的时候,就执行了WorkerRunnable中的call方法,call中又调用doInbackground,然后postResult发送消息,又回到了上面的分析。
run执行完毕之后,会判断mActive是否为空,第一次肯定为空,执行scheduleNext方法

protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }

调用了mTasks的poll方法从当前队列头部取出消息,给线程执行器执行,以后mActive就不为null,我们可以看到scheduleNext放到了finally方法里面,保证了每次都会执行。

好了,AsyncTask的源码就分析到这里了,已经快吐血了,费了不少时间,脑子现在还是有点乱,最后大概总结一下下面这句话都干了啥

 new MyTask().execute();

1.创建对象(new MyTask())
创建WorkerRunnable对象(Callable),重写call方法—->将WorkerRunnable传递给FutureTask
2.执行任务(execute())
execute(Params… params)—->executeOnExecutor(Executor exec,
Params… params) —->调用onPreExecute—->调用SerialExecutor的execute方法,传入上面的FutureTask对象,请注意,这个FutureTask包装了WorkerRunnable对象,可不简单哦—->调用FutureTask的run方法(run方法里面调用了call)—->调用WorkerRunnable的call方法—->调用scheduleNext执行下个任务

最后说一下AsyncTask版本上的差异

在1.6之前,AsyncTask是串行执行任务的,1.6的时候AsyncTask开始采用线程池里处理并行任务,但是从3.0开始,为了避免AsyncTask所带来的并发错误,AsyncTask又采用一个线程来串行执行任务

那么我们现在有没有办法让AsyncTask并行执行呢》有
在Anddroid3.0以后的AsyncTask类给暴露出一个接口也就是上面的executeOnExecutor方法啦,我们只需要重新构造一个线程池执行器,比如说你可以调用newCachedThreadPool方法来创建一个无线大的缓存线程池,可以同时执行无线个任务。

//构建一个缓存线程池,用于同时执行无限多个异步耗时任务
ExecutorService executorService = Executors.newCachedThreadPool();
asyncTask.executeOnExecutor(executorService,params);

开发者可以根据项目需求选择自己合适的线程池执行器:

Single Thread Executor : 只有一个线程的线程池,因此所有提交的任务是顺序执行,代码: Executors.newSingleThreadExecutor()

Cached Thread Pool : 线程池里有很多线程需要同时执行,老的可用线程将被新的任务触发重新执行,如果线程超过60秒内没执行,那么将被终
止并从池中删除,代码:Executors.newCachedThreadPool()

Fixed Thread Pool : 拥有固定线程数的线程池,如果没有任务执行,那么线程会一直等待,代码: Executors.newFixedThreadPool()

Scheduled Thread Pool : 用来调度即将执行的任务的线程池,代码:Executors.newScheduledThreadPool()

Single Thread Scheduled Pool : 只有一个线程,用来调度执行将来的任务,代码:Executors.newSingleThreadScheduledExecutor()

Android异步处理框架AsyncTask源码解析

标签:

原文地址:http://blog.csdn.net/small_lee/article/details/51297308

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!