深入解析AsyncTask

Android 1.5提供了一个工具类:AsyncTask,它使创建需要与用户界面交互的长时间运行的任务变得更简单。相对来说AsyncTask更轻量级一些,适用于简单的异步处理,不需要借助线程和Handler即可实现。 AsyncTask的功能在不在这里介绍。

3.0之前一直以来都是以下面的方式执行AsyncTask任务:

new AsyncTask<Void, Void, Void>() {

            @Override
            protected Void doInBackground(Void... params) {
                // 处理耗时操作
                return null;
            }
        }.execute();

3.0以上的手机上执行AsyncTask都不会使用上面的方式执行了,3.0以上的AsyncTask默认是单线程执行了。

所以要适配不同版本的手机,应该使用下面的工具类执行AsyncTask任务:

public class CommonUtils {
    public static <Params, Progress, Result> void executeAsyncTask(
            AsyncTask<Params, Progress, Result> task, Params... params) {
        if (Build.VERSION.SDK_INT >= 11) {
            task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
        } else {
            task.execute(params);
        }
    }
}

用法示例:

CommonUtils.executeAsyncTask(new AsyncTask<Void, Void, Void>() {

            @Override
            protected Void doInBackground(Void... params) {
                // 处理耗时操作
                return null;
            }
        });

在3.0之后 执行execute默认会调用sDefaultExecutor

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

sDefaultExecutor是一功能类似单线程池。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;

    private static final InternalHandler sHandler = new InternalHandler();

    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

下面看看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);
        }
    }
} 

可以看到,SerialExecutor是使用ArrayDeque这个队列来管理Runnable对象的,如果我们一次性启动了很多个任务,首先在第一次运行execute()方法的时候,会调用ArrayDeque的offer()方法将传入的Runnable对象添加到队列的尾部,然后判断mActive对象是不是等于null,第一次运行当然是等于null了,于是会调用scheduleNext()方法。在这个方法中会从队列的头部取值,并赋值给mActive对象,然后调用THREAD_POOL_EXECUTOR去执行取出的取出的Runnable对象。之后如何又有新的任务被执行,同样还会调用offer()方法将传入的Runnable添加到队列的尾部,但是再去给mActive对象做非空检查的时候就会发现mActive对象已经不再是null了,于是就不会再调用scheduleNext()方法。

那么后面添加的任务岂不是永远得不到处理了?当然不是,看一看offer()方法里传入的Runnable匿名类,这里使用了一个try finally代码块,并在finally中调用了scheduleNext()方法,保证无论发生什么情况,这个方法都会被调用。也就是说,每次当一个任务执行完毕后,下一个任务才会得到执行,SerialExecutor模仿的是单一线程池的效果,如果我们快速地启动了很多任务,同一时刻只会有一个线程正在执行,其余的均处于等待状态。

不过你可能还不知道,在Android 3.0之前是并没有SerialExecutor这个类的,那个时候是直接在AsyncTask中构建了一个sExecutor常量,并对线程池总大小,同一时刻能够运行的线程数做了规定,代码如下所示:

而3.0之后的AsyncTask默认同时只能有1个任务在执行。3.0为了增加不同的需求,增强扩展性,变得更加灵活。如果不想使用默认的线程池,还可以自由地进行配置。比如使用如下的代码来启动任务:

Executor exec = new ThreadPoolExecutor(15, 200, 10,
        TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
new DownloadTask().executeOnExecutor(exec);  

这样就可以使用我们自定义的一个Executor来执行任务,而不是使用SerialExecutor。上述代码的效果允许在同一时刻有15个任务正在执行,并且最多能够存储200个任务。

好了,到这里我们就已经把关于AsyncTask的所有重要内容深入浅出地理解了一遍,相信在将来使用它的时候能够更加得心应手。

4.3系统

4.4系统的

CORE_POOL_SIZE变成了CPU个数+1。

MAXIMUM_POOL_SIZE变成了2倍的CPU+1

原来的sPoolWorkQueue1在4.4之前队列都是大小为10,4.4之后队列大小是128

深入解析AsyncTask,布布扣,bubuko.com

时间: 2024-08-06 16:00:56

深入解析AsyncTask的相关文章

Android_深入解析AsyncTask

转载:特别感谢浪人的星空,有部分修改! http://blog.csdn.net/hitlion2008/article/details/7983449 1.AsyncTask的内幕 AsyncTask主要有二个部分:一个是与主线各的交互,另一个就是线程的管理调度.虽然可能多个AsyncTask的子类的实例,但是AsyncTask的内部Handler和ThreadPoolExecutor都是进程范围内共享的,其都是static的,也即属于类的,类的属性的作用范围是CLASSPATH,因为一个进程

Android实战技巧:深入解析AsyncTask

AsyncTask的介绍及基本使用方法 关于AsyncTask的介绍和基本使用方法可以参考官方文档和Android实战技巧:多线程AsyncTask这里就不重复. AsyncTask引发的一个问题 上周遇到了一个极其诡异的问题,一个小功能从网络上下载一个图片,然后放到ImageView中,是用AsyncTask来实现的,本身逻辑也很简单,仅是在doInBackground中用HTTP请求把图片的输入流取出,然后用BitmapFactory去解析,然后再把得到的Bitmap放到ImageView中

一步步完全解析AsyncTask

做个Android开发的同学们应该都用过AsyncTask,通过继承AsyncTask类实现异步操作,反馈当前异步执行的进度,最后执行的结果反馈给UI主线程.我们在开发中使用AsyncTask,因为它的主要优点使用简单方便.不用关系和主线程交互逻辑和执行过程可控,当然还可以支持取消.说完AsyncTask的优点,下面我们来数数AsyncTask的几宗罪. 1.不同版本实现对并发支持不一,需要控制线程任务先后的情况难以控制,当我们开发中要求两个任务必须有先后执行顺序,我们Android2.3版本A

解析AsyncTask&lt;Params, Progress, Result&gt;()

1.AsyncTask中方法的执行顺序为 ①首先执行的是execute(params),new AsyncTask<Params, Progress, Result>(){}.execute(params); ②其次是执行protected Result onPreExecute(),这个方法是在主线程中运行 ③再者是doInBackground(String... params),这个方法在子线程中运行 ④最后是onPostExecute(String result),这个方法也是在主线程中

Android AsyncTask 源码解析

1. 官方介绍 public abstract class AsyncTask extends Object  java.lang.Object    ? android.os.AsyncTask<Params, Progress, Result> AsyncTask enables proper and easy use of the UI thread. This class allows to perform background operations and publish resul

android源码解析之(二)--&gt;异步任务AsyncTask

android的异步任务体系中还有一个非常重要的操作类:AsyncTask,其内部主要使用的是java的线程池和Handler来实现异步任务以及与UI线程的交互.本文主要解析AsyncTask的的使用与源码. 首先我们来看一下AsyncTask的基本使用: class MAsyncTask extends AsyncTask<Integer, Integer, Integer> { @Override protected void onPreExecute() { super.onPreExe

Android异步加载AsyncTask详解

最近项目发现个重大问题,结果打log跟踪查是AsyncTask导致的.如果对AsyncTask了解的不够深入透彻,那写代码就是埋雷.以后不定在哪个时间爆炸.首先我们要了解,谷歌为什么发明AsyncTask,AsyncTask到底是用来解决什么问题的?Android有一个原则---单线程模型的原则:UI操作并不是线程安全的并且这些操作必须在UI线程中执行. 在单线程模型中始终要记住两条法则: 1. 不要阻塞UI线程 2. 确保只在UI线程中访问Android UI工具包 首先来说说AsyncTas

Android异步载入AsyncTask具体解释

曾看见有人说过.认为非常有道理.分享一下:   技术分为术和道两种:   (1)具体做事的方法是术.   (2)做事的原理和原则是道. 近期项目发现个重大问题.结果打log跟踪查是AsyncTask导致的.假设对AsyncTask了解的不够深入透彻.那写代码就是埋雷.以后不定在哪个时间爆炸.首先我们要了解,谷歌为什么发明AsyncTask,AsyncTask究竟是用来解决什么问题的?Android有一个原则---单线程模型的原则:UI操作并非线程安全的并且这些操作必须在UI线程中运行. 所以谷歌

AsyncTask RejectedExecutionException 小结

在使用Asynctask时,相信有些朋友会遇到以下RejectedExecutionException: Java.util.concurrent.RejectedExecutionException: Task [email protected] rejected from [email protected][Running, pool size = 9, active threads = 9, queued tasks = 128, completed tasks = 0] at andro