zoukankan      html  css  js  c++  java
  • 深入解析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

  • 相关阅读:
    序列化-请求数据校验。。。。。。
    python自动化测试-D5-学习笔记之二(常用模块之加密模块)
    python自动化测试-D5-学习笔记之二(常用模块之os,sys,random,string,time)
    python自动化测试-D5-学习笔记之二(常用模块之json模块)
    python自动化测试-D5-学习笔记之一(argv的使用)
    python自动化测试-D5-学习笔记之一(函数补充,内置函数,map,filter,eval)
    python习题:写一个函数打印两个字典中不一样的key和value
    python习题:用文件方式编写购物车程序,添加,查看和删除
    python习题:时间格式转换
    python习题:双色球
  • 原文地址:https://www.cnblogs.com/mingfeng002/p/3708141.html
Copyright © 2011-2022 走看看