Android Asynctask与Handler的比较,优缺点区别,Asynctask源码

来源:互联网 发布:软件合作开发合同范本 编辑:程序博客网 时间:2024/05/01 21:37

1  AsyncTask实现的原理,和适用的优缺点

AsyncTask,是android提供的轻量级的异步类,可以直接继承AsyncTask,在类中实现异步操作,提供接口反馈当前异步执行的程度(可以通过接口实现UI进度更新),最后反馈执行的结果给UI主线程.

使用的优点:

l  简单,快捷

l  过程可控

使用的缺点:

l  在使用多个异步操作和并需要进行Ui变更时,就变得复杂起来.

2 Handler异步实现的原理和适用的优缺点

在Handler 异步实现时,涉及到 Handler, Looper, Message,Thread四个对象,实现异步的流程是主线程启动Thread(子线程)àthread(子线程)运行并生成Message- àLooper获取Message并传递给HandleràHandler逐个获取Looper中的Message,并进行UI变更。

使用的优点:

l  结构清晰,功能定义明确

l  对于多个后台任务时,简单,清晰

 

AsyncTask这个类感觉使用比较简单,就是实现其中几个方法,onPreExecute()方法是在任务刚开始运行时执行的一些初始化操作,比如初 始化一个进度条等等,然后就执行doInBackground()方法这里面主要放业务操作,比如查询数据库等,在这个方法执行的时候会调用 onProgressUpdate(),可以在这个方法中更新UI界面,最后是调用onPostExecute()方法,当得到业务结果后就可以在这个方 法中返回给UI线程,也可以关闭一些执行这个业务时开的一些资源。大家可以看得出AsyncTask这个类是一个泛型类,这个类的三个参数以此对应 doInBackground(String... params),onProgressUpdate(String... values),onPostExecute(String result)的参数,很形象的···如果不需要传参和返回值,可以用Void代替。而doInBackground(String... params)方法的返回值也就是onPostExecute(String result)方法的参数值,因为doInBackground方法执行后返回的值是在onPostExecute(String result)中处理的。

用handler方式处理需要知道与handler相关的几个组件,Looper和Queue,其实Looper的作用就是把handler发送的消息放 到Queue中,并把消息广播给所有与这个Queue相关的handler,而Queue一般是主线程开启的时候就给这个线程分配了一个,所以你要与UI 主线程通信必须用于这个Queue相关联的handler对象才行,一般handler对象在那个线程中创建的就与那个线程的queue关联,所以在UI 线程中创建的handler对象就与UI线程通讯,这样我们就可以在子线程中发送消息给主线程,实现更新UI的功能。那主线程又是怎么处理子线程发送的消 息的呢?其实在生成handler对象的时候我们就要实现handler对象的handleMessage()方法这个方法就是主线程接受并处理子线程发 送过来的消息的方法,从而实现 更新UI线程的功能。

 

很多网友可能发现android平台很多应用使用的都是AsyncTask,而并非Thread和Handler去更新UI,这里给大家说下他们到底有什 么区别,我们平时应该使用哪种解决方案。从Android 1.5开始系统将AsyncTask引入到android.os包中,过去在很早1.1和1.0 SDK时其实官方将其命名为UserTask,其内部是JDK 1.5开始新增的concurrent库,做过J2EE的网友可能明白并发库效率和强大性,比Java原始的Thread更灵活和强大,但对于轻量级的使 用更为占用系统资源。Thread是Java早期为实现多线程而设计的,比较简单不支持concurrent中很多特性在同步和线程池类中需要自己去实现 很多的东西,对于分布式应用来说更需要自己写调度代码,而为了android UI的刷新Google引入了Handler和Looper机制,它们均基于消息实现,有时可能消息队列阻塞或其他原因无法准确的使用。

推荐大家使用AsyncTask代替Thread+Handler的方式,不仅调用上更为简单,经过实测更可靠一些,Google在Browser中大量 使用了异步任务作为处理耗时的I/O操作,比如下载文件、读写数据库等等,它们在本质上都离不开消息,但是AsyncTask相比Thread加 Handler更为可靠,更易于维护,但AsyncTask缺点也是有的比如一旦线程开启即dobackground方法执行后无法给线程发送消息,仅能 通过预先设置好的标记来控制逻辑,当然可以通过线程的挂起等待标志位的改变来通讯,对于某些应用Thread和Handler以及Looper可能更灵 活。

 

 

本文主要讲解下AsyncTask的使用以及Handler的应用

首先,我们得明确下一个概念,什么是UI线程。顾名思义,ui线程就是管理着用户界面的那个线程!

android的ui线程操作并不是安全的,并且和用户直接进行界面交互的操作都必须在ui线程中进行才可以。这种模式叫做单线程模式。

我们在单线程模式下编程一定要注意:不要阻塞ui线程、确保只在ui线程中访问ui组件

当我们要执行一个复杂耗时的算法并且最终要将计算结果反映到ui上时,我们会发现,我们根本没办法同时保证上面的两点要求;我们肯定会想到开启一个新的线程,让这个复杂耗时的任务到后台去执行,但是执行完毕了呢?我们发现,我们无法再与ui进行交互了。

为了解决这种情况,android为我们提供了很多办法。

1)、handler和message机制:通过显示的抛出、捕获消息与ui进行交互;

2)、Activity.runOnUiThread(Runnable):如果当前线程为ui线程,则立即执行;否则,将参数中的线程操作放入到ui线程的事件队列中,等待执行。

3)、View.post(Runnable):将操作放入到message队列中,如果放入成功,该操作将会在ui线程中执行,并返回true,否则返回false

4)、View.postDelayed(Runnable, long)跟第三条基本一样,只不过添加了一个延迟时间。

5)、android1.5以后为我们提供了一个工具类来搞定这个问题AsyncTask.

AsyncTask是抽象类,定义了三种泛型类型 Params,Progress,Result。

Params 启动任务执行的输入参数,比如HTTP请求的URL

Progress 后台任务执行的百分比。

Result 后台执行任务最终返回的结果,比如String

用程序调用,开发者需要做的就是实现这些方法。

1) 子类化AsyncTask

2) 实现AsyncTask中定义的下面一个或几个方法

onPreExecute(),该方法将在执行实际的后台操作前被UI thread调用。可以在该方法中做一些准备工作,如在界面上显示一个进度条。

doInBackground(Params…),将在onPreExecute 方法执行后马上执行,该方法运行在后台线程中。这里将主要负责执行那些很耗时的后台计算工作。可以调用 publishProgress方法来更新实时的任务进度。该方法是抽象方法,子类必须实现。

onProgressUpdate(Progress…),在publishProgress方法被调用后,UI thread将调用这个方法从而在界面上展示任务的进展情况,例如通过一个进度条进行展示。

onPostExecute(Result),在doInBackground 执行完成后,onPostExecute 方法将被UI thread调用,后台的计算结果将通过该方法传递到UI thread.

为了正确的使用AsyncTask类,以下是几条必须遵守的准则:

1) Task的实例必须在UI thread中创建

2) execute方法必须在UI thread中调用

3) 不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params…), onProgressUpdate(Progress…)这几个方法

4) 该task只能被执行一次,否则多次调用时将会出现异常


下面介绍最本质的多线程:hanlder和message机制:

为何需要多线程:

在日常应用中,我们通常需要处理一些“后台,用户不可见”的操作,例如说,我们需要下载一个音乐,要是你的应用必须等用户下载完成之后才可以进行别的操 作,那肯定让用户非常的不爽。这时候,我们通常的做法是,让这些操作去后台执行,然后等后台执行完毕之后,再给用户弹出相应的提示信息。这时候,我们就需 要使用多线程机制,然后通过创建一个新的线程来执行这些操作。

明白了,实现需求,我们就准备着手实现了。但是,经过进一步的了解,我们悲剧的发现,android中的线程机制是,只能在UI线程中和用户进行交互。当 我们创建了一个新线程,执行了一些后台操作,执行完成之后,我们想要给用户弹出对话框以确认,但是却悲剧的发现,我们根本无法返回UI主线程了。

(说明:何为UI线程:UI线程就是你当前看到的这些交互界面所属的线程)。

这时候,我们如果想要实现这些功能,我们就需要一个android为我们提供的handler和message机制。

先讲解下编程机制:

我们通常在UI线程中创建一个handler,handler相当于一个处理器,它主要负责处理和绑定到该handler的线程中的message。每一 个handler都必须关联一个looper,并且两者是一一对应的,注意,这点很重要哦!此外,looper负责从其内部的messageQueue中 拿出一个个的message给handler进行处理。因为我们这里handler是在UI线程中实现的,所以经过这么一个handler、 message机制,我们就可以回到UI线程中了。

何为handler:处理后台进程返回数据的工作人员。

何为message:后台进程返回的数据,里面可以存储bundle等数据格式

何为messageQueue:是线程对应looper的一部分,负责存储从后台进程中抛回的和当前handler绑定的message,是一个队列。

何为looper:looper相当于一个messageQueue的管理人员,它会不停的循环的遍历队列,然后将符合条件的message一个个的拿出来交给handler进行处理。

注意,handler是在UI线程中声明的,如果我们直接用类似代码执行一个线程的话,实际上并没有创建一个新的线程,因为handler已经跟默认的UI线程中的looper绑定了。

如果有兴趣的话,可以去看下Handler的默认空构造函数便知道原因了,里面直接绑定了当前UI线程的looper。

下面给出一个比较简单,并且实用的实例。

这2种方式都可以实现,但是他们的区别在哪里?优缺点各是什么?

    (1)、AsyncTask是封装好的线程池,比起Thread+Handler的方式,AsyncTask在操作UI线程上更方便,因为onPreExecute()、onPostExecute()及更新UI方法onProgressUpdate()均运行在主线程中,这样就不用Handler发消息处理了;

    (2)、我不太同意封装好就会影响性能的说法,在我实际的运用中,真正的缺点来自于AsyncTask的全局线程池只有5个工作线程,也就是说,一个APP如果运用AsyncTask技术来执行线程,那么同一时间最多只能有5个线程同时运行,其他线程将被阻塞(注:不运用AsyncTask执行的线程,也就是自己new出来的线程不受此限制),所以AsyncTask不要用于多线程取网络数据,因为很可能这样会产生阻塞,从而降低效率。

    三. 能否同时并发100+asynctask呢?

    AsyncTask用的是线程池机制,容量是128,最多同时运行5个core线程,剩下的排队。

2、AsyncTask是否异步

public class MainService extends Service{private static Task task;//当前执行任务private static Map<String, Activity> allActivitys = <a target=_blank href="http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=0&is_app=0&jk=ef0bb49edecdbe09&k=new&k0=new&kdi0=0&luki=3&mcpm=0&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=9becdde9eb40bef&ssp2=1&stid=9&t=tpclicked3_hc&td=1836545&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D577651%2Ehtml&urlid=0" target="_blank" style="padding: 0px; color: rgb(51, 136, 255); text-decoration: none;">new</a> HashMap<String, Activity>();//缓存activity集合private static ExecutorService exec = Executors.newSingleThreadExecutor();@Overridepublic void onStart(Intent intent, int startId) {super.onStart(intent, startId);MainAsyncTask asyncTask = <a target=_blank href="http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=0&is_app=0&jk=ef0bb49edecdbe09&k=new&k0=new&kdi0=0&luki=3&mcpm=0&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=9becdde9eb40bef&ssp2=1&stid=9&t=tpclicked3_hc&td=1836545&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D577651%2Ehtml&urlid=0" target="_blank" style="padding: 0px; color: rgb(51, 136, 255); text-decoration: none;">new</a> MainAsyncTask();//asyncTask.execute(task);//asyncTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, task);//asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, task);//asyncTask.executeOnExecutor(Executors.<a target=_blank href="http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=0&is_app=0&jk=ef0bb49edecdbe09&k=new&k0=new&kdi0=0&luki=3&mcpm=0&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=9becdde9eb40bef&ssp2=1&stid=9&t=tpclicked3_hc&td=1836545&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D577651%2Ehtml&urlid=0" target="_blank" style="padding: 0px; color: rgb(51, 136, 255); text-decoration: none;">new</a>FixedThreadPool(2), task);asyncTask.executeOnExecutor(exec, task);}private final class MainAsyncTask extends AsyncTask<Object, Integer, Object>{private Task task;@Overrideprotected Object doInBackground(Object... params) {Object result = null;task = (Task)params[0];<a target=_blank href="http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=0&is_app=0&jk=ef0bb49edecdbe09&k=switch&k0=switch&kdi0=0&luki=8&mcpm=0&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=9becdde9eb40bef&ssp2=1&stid=9&t=tpclicked3_hc&td=1836545&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D577651%2Ehtml&urlid=0" target="_blank" style="padding: 0px; color: rgb(51, 136, 255); text-decoration: none;">switch</a> (task.getTaskID()) {case Task.TASK_USER_LOGIN:try {Thread.sleep(3000);System.out.println("任务"+task.getTaskID()+" Thread id: "+Thread.currentThread().getId());} catch (InterruptedException e) {e.printStackTrace();}break;case 2:System.out.println("任务"+task.getTaskID()+" Thread id: "+Thread.currentThread().getId());break;}return result;}@Overrideprotected void onPostExecute(Object result) {super.onPostExecute(result);ActivityInterFace aif;<a target=_blank href="http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=0&is_app=0&jk=ef0bb49edecdbe09&k=switch&k0=switch&kdi0=0&luki=8&mcpm=0&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=9becdde9eb40bef&ssp2=1&stid=9&t=tpclicked3_hc&td=1836545&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D577651%2Ehtml&urlid=0" target="_blank" style="padding: 0px; color: rgb(51, 136, 255); text-decoration: none;">switch</a> (task.getTaskID()) {case Task.TASK_USER_LOGIN:aif = (ActivityInterFace)allActivitys.get("LoginActivity");aif.refresh(1, result);break;case 2:aif = (ActivityInterFace)allActivitys.get("LoginActivity");aif.refresh(2, result);break;default:break;}}}/** * 添加新任务 * @param task */public static void addTask(Context context, Task task) {MainService.task = task;context.startService(<a target=_blank href="http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=0&is_app=0&jk=ef0bb49edecdbe09&k=new&k0=new&kdi0=0&luki=3&mcpm=0&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=9becdde9eb40bef&ssp2=1&stid=9&t=tpclicked3_hc&td=1836545&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D577651%2Ehtml&urlid=0" target="_blank" style="padding: 0px; color: rgb(51, 136, 255); text-decoration: none;">new</a> Intent("mainService"));}/** * 缓存activity * @param activity */public static void addActivity(Activity activity) {String path = activity.getClass().getName();String name = path.substring(path.lastIndexOf(".")+1);allActivitys.put(name, activity);}@Overridepublic IBinder onBind(Intent intent) {return null;}}

当我执行两次调用asyncTask.execute(task);时发现只有当第一次的任务完成后才执行下一下任务!!怎么回事?

AyncTask不是号称异步线程池吗?既然是线程池那么多任务执行时应该可以并发执行啊,至少两个任务可以并发执

行,以前看过一个视频,人家的就可以啊!纠结了一下午,通过查阅资料和自己的动手实验终于把问题搞明白了。

    原来在SDK3.0以前的版本执行asyncTask.execute(task);时的确是多线程并发执行的,线程池大小为5,最大可大

128个,google在3.0以后的版本中做了修改,将asyncTask.execute(task);修改为了顺序执行,即只有当一个的实

的任务完成后在执行下一个实例的任务。

    那么怎么才能并发执行呢,很简单,3.0后新增了一个方法executeOnExecutor(Executor
exec, 
Object... params),

该方法接受2个参数,第一个是Executor,第二个是任务参数。第一个是线程池实例,google为我们预定义了两种:

一种是AsyncTask.SERIAL_EXECUTOR,第二种是AsyncTask.THREAD_POOL_EXECUTOR,顾名思义,第一

其实就像3.0以后的execute方法,是顺序执行的。第二种就是3.0以前的execute方法,是可以并发执行的。我们直

接用asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, task);就可以多任务并发执行了。

    既然executeOnExecutor第一个参数是Executor,那么我们可以自定义Executor吗?当然可以,Executor主要由四

类型newCachedThreadPool,newFixedThreadPool,newScheduledThreadPool,newSingleThreadExecutor

(具体使用解析可以看我上一篇文章点击打开链接),可是当我这样使用

asyncTask.executeOnExecutor(Executors.newFixedThreadPool(1), task);或者

asyncTask.executeOnExecutor(Executors.newSingleThreadExecutor, task);并没有像我想象的与

asyncTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, task);那样是单线程顺序执行,而是像

asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, task);是多线程并发执行的,我不是

已经规定newFixedThreadPool的线程池数量是1或者是newSingleThreadExecutor单线程了么!怎么回事呢?原来程

序在每次调用asyncTask.executeOnExecutor(Executors.newFixedThreadPool(2), task)时会获取一个新的Executor对

象,这个对象内的线程只执行对应的task,所以无论哪种情况每个task都有一个新的线程来执行,即并发执行。

知道原因就好办了,我们定义个一全局静态变量

private static ExecutorService exec = Executors.newSingleThreadExecutor();程序在每次调用

asyncTask.executeOnExecutor(exec, task);时是使用的同一个Executor,执行效果如下:

当Executor类型为:private static ExecutorService exec = Executors.newFixedThreadPool(2);只有两个线程在执行

任务

技术分享

当Executor类型为:private static ExecutorService exec = Executors.newSingleThreadExecutor();只有一个线程在执行任务

技术分享

3、AsyncTask源码分析

public abstract class AsyncTask {    private static final String LOG_TAG = AsyncTask;//获取当前的cpu核心数    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();//线程池核心容量    private static final int CORE_POOL_SIZE = CPU_COUNT + 1;//线程池最大容量    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;//过剩的空闲线程的存活时间    private static final int KEEP_ALIVE = 1;//ThreadFactory 线程工厂,通过工厂方法<a target=_blank href="http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=0&is_app=0&jk=ef0bb49edecdbe09&k=new&k0=new&kdi0=0&luki=3&mcpm=0&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=9becdde9eb40bef&ssp2=1&stid=9&t=tpclicked3_hc&td=1836545&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D577651%2Ehtml&urlid=0" target="_blank" style="padding: 0px; color: rgb(51, 136, 255); text-decoration: none;">new</a>Thread来获取新线程    private static final ThreadFactory sThreadFactory = new ThreadFactory() {//原子整数,可以在超高并发下正常工作        private final AtomicInteger mCount = new AtomicInteger(1);        public Thread <a target=_blank href="http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=0&is_app=0&jk=ef0bb49edecdbe09&k=new&k0=new&kdi0=0&luki=3&mcpm=0&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=9becdde9eb40bef&ssp2=1&stid=9&t=tpclicked3_hc&td=1836545&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D577651%2Ehtml&urlid=0" target="_blank" style="padding: 0px; color: rgb(51, 136, 255); text-decoration: none;">new</a>Thread(Runnable r) {            return new Thread(r, AsyncTask # + mCount.getAndIncrement());        }    };//静态阻塞式队列,用来存放待执行的任务,初始容量:128个    private static final BlockingQueue sPoolWorkQueue =            new LinkedBlockingQueue(128);    /**     * 静态并发线程池,可以用来并行执行任务,尽管从3.0开始,AsyncTask默认是串行执行任务 * 但是我们仍然能构造出并行的AsyncTask     */    public static final Executor THREAD_POOL_EXECUTOR            = <a target=_blank href="http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=0&is_app=0&jk=ef0bb49edecdbe09&k=new&k0=new&kdi0=0&luki=3&mcpm=0&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=9becdde9eb40bef&ssp2=1&stid=9&t=tpclicked3_hc&td=1836545&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D577651%2Ehtml&urlid=0" target="_blank" style="padding: 0px; color: rgb(51, 136, 255); text-decoration: none;">new</a> ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);    /**     * 静态串行任务执行器,其内部实现了串行控制, * 循环的取出一个个任务交给上述的并发线程池去执行     */    public static final Executor SERIAL_EXECUTOR = <a target=_blank href="http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=0&is_app=0&jk=ef0bb49edecdbe09&k=new&k0=new&kdi0=0&luki=3&mcpm=0&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=9becdde9eb40bef&ssp2=1&stid=9&t=tpclicked3_hc&td=1836545&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D577651%2Ehtml&urlid=0" target="_blank" style="padding: 0px; color: rgb(51, 136, 255); text-decoration: none;">new</a> SerialExecutor();//消息类型:发送结果    private static final int MESSAGE_POST_RESULT = 0x1;//消息类型:更新进度    private static final int MESSAGE_POST_PROGRESS = 0x2;/**静态Handler,用来发送上述两种通知,采用UI线程的Looper来处理消息 * 这就是为什么AsyncTask必须在UI线程调用,因为子线程 * 默认没有Looper无法创建下面的Handler,程序会直接Crash */    private static final InternalHandler sHandler = <a target=_blank href="http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=0&is_app=0&jk=ef0bb49edecdbe09&k=new&k0=new&kdi0=0&luki=3&mcpm=0&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=9becdde9eb40bef&ssp2=1&stid=9&t=tpclicked3_hc&td=1836545&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D577651%2Ehtml&urlid=0" target="_blank" style="padding: 0px; color: rgb(51, 136, 255); text-decoration: none;">new</a> InternalHandler();//默认任务执行器,被赋值为串行任务执行器,就是它,AsyncTask变成串行的了    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;//如下两个变量我们先不要深究,不影响我们对整体逻辑的理解    private final WorkerRunnable mWorker;    private final FutureTask mFuture;//任务的状态 默认为挂起,即等待执行,其类型标识为易变的(volatile)    private volatile Status mStatus = Status.PENDING;    //原子布尔型,支持高并发访问,标识任务是否被取消    private final AtomicBoolean mCancelled = <a target=_blank href="http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=0&is_app=0&jk=ef0bb49edecdbe09&k=new&k0=new&kdi0=0&luki=3&mcpm=0&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=9becdde9eb40bef&ssp2=1&stid=9&t=tpclicked3_hc&td=1836545&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D577651%2Ehtml&urlid=0" target="_blank" style="padding: 0px; color: rgb(51, 136, 255); text-decoration: none;">new</a> AtomicBoolean();//原子布尔型,支持高并发访问,标识任务是否被执行过    private final AtomicBoolean mTaskInvoked = <a target=_blank href="http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=0&is_app=0&jk=ef0bb49edecdbe09&k=new&k0=new&kdi0=0&luki=3&mcpm=0&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=9becdde9eb40bef&ssp2=1&stid=9&t=tpclicked3_hc&td=1836545&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D577651%2Ehtml&urlid=0" target="_blank" style="padding: 0px; color: rgb(51, 136, 255); text-decoration: none;">new</a> AtomicBoolean();/*串行执行器的实现,我们要好好看看,它是怎么把并行转为串行的 *目前我们需要知道,asyncTask.execute(Params ...)实际上会调用 *SerialExecutor的execute方法,这一点后面再说明。也就是说:当你的asyncTask执行的时候, *首先你的task会被加入到任务队列,然后排队,一个个执行 */    private static class SerialExecutor implements Executor {//线性双向队列,用来存储所有的AsyncTask任务        final ArrayDeque mTasks = <a target=_blank href="http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=0&is_app=0&jk=ef0bb49edecdbe09&k=new&k0=new&kdi0=0&luki=3&mcpm=0&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=9becdde9eb40bef&ssp2=1&stid=9&t=tpclicked3_hc&td=1836545&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D577651%2Ehtml&urlid=0" target="_blank" style="padding: 0px; color: rgb(51, 136, 255); text-decoration: none;">new</a> ArrayDeque();//当前正在执行的AsyncTask任务        Runnable mActive;        public synchronized void execute(final Runnable r) {//将新的AsyncTask任务加入到双向队列中            mTasks.offer(new Runnable() {                public void run() {                    try {//执行AsyncTask任务                        r.run();                    } finally {//当前AsyncTask任务执行完毕后,进行下一轮执行,如果还有未执行任务的话//这一点很明显体现了AsyncTask是串行执行任务的,总是一个任务执行完毕才会执行下一个任务                        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,    }    /** 隐藏API:在UI线程中调用,用来初始化Handler */    public static void init() {        sHandler.getLooper();    }    /** 隐藏API:为AsyncTask设置默认执行器 */    public static void setDefaultExecutor(Executor exec) {        sDefaultExecutor = exec;    }    /**     * Creates a <a target=_blank href="http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=0&is_app=0&jk=ef0bb49edecdbe09&k=new&k0=new&kdi0=0&luki=3&mcpm=0&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=9becdde9eb40bef&ssp2=1&stid=9&t=tpclicked3_hc&td=1836545&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D577651%2Ehtml&urlid=0" target="_blank" style="padding: 0px; color: rgb(51, 136, 255); text-decoration: none;">new</a> asynchronous task. This constructor must be invoked on the UI thread.     */    public AsyncTask() {        mWorker = <a target=_blank href="http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=0&is_app=0&jk=ef0bb49edecdbe09&k=new&k0=new&kdi0=0&luki=3&mcpm=0&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=9becdde9eb40bef&ssp2=1&stid=9&t=tpclicked3_hc&td=1836545&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D577651%2Ehtml&urlid=0" target="_blank" style="padding: 0px; color: rgb(51, 136, 255); text-decoration: none;">new</a> WorkerRunnable() {            public Result call() throws Exception {                mTaskInvoked.set(true);                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);                //noinspection unchecked                return postResult(doInBackground(mParams));            }        };        mFuture = <a target=_blank href="http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=0&is_app=0&jk=ef0bb49edecdbe09&k=new&k0=new&kdi0=0&luki=3&mcpm=0&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=9becdde9eb40bef&ssp2=1&stid=9&t=tpclicked3_hc&td=1836545&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D577651%2Ehtml&urlid=0" target="_blank" style="padding: 0px; color: rgb(51, 136, 255); text-decoration: none;">new</a> FutureTask(mWorker) {            @Override            protected void done() {                try {                    postResultIfNotInvoked(get());                } catch (InterruptedException e) {                    <a target=_blank href="http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=0&is_app=0&jk=ef0bb49edecdbe09&k=android&k0=android&kdi0=0&luki=1&mcpm=0&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=9becdde9eb40bef&ssp2=1&stid=9&t=tpclicked3_hc&td=1836545&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D577651%2Ehtml&urlid=0" target="_blank" style="padding: 0px; color: rgb(51, 136, 255); text-decoration: none;">android</a>.util.Log.w(LOG_TAG, e);                } catch (ExecutionException e) {                    throw new RuntimeException(An error occured while executing doInBackground(),                            e.getCause());                } catch (CancellationException e) {                    postResultIfNotInvoked(null);                }            }        };    }    private void postResultIfNotInvoked(Result result) {        final boolean wasTaskInvoked = mTaskInvoked.get();        if (!wasTaskInvoked) {            postResult(result);        }    }//doInBackground执行完毕,发送消息    private Result postResult(Result result) {        @SuppressWarnings(unchecked)        Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,                <a target=_blank href="http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=0&is_app=0&jk=ef0bb49edecdbe09&k=new&k0=new&kdi0=0&luki=3&mcpm=0&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=9becdde9eb40bef&ssp2=1&stid=9&t=tpclicked3_hc&td=1836545&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D577651%2Ehtml&urlid=0" target="_blank" style="padding: 0px; color: rgb(51, 136, 255); text-decoration: none;">new</a> AsyncTaskResult(this, result));        message.sendToTarget();        return result;    }    /**     * 返回任务的状态     */    public final Status getStatus() {        return mStatus;    }    /** * 这个方法是我们必须要重写的,用来做后台计算 * 所在线程:后台线程     */    protected abstract Result doInBackground(Params... params);    /** * 在doInBackground之前调用,用来做初始化工作 * 所在线程:UI线程     */    protected void onPreExecute() {    }    /** * 在doInBackground之后调用,用来接受后台计算结果更新UI * 所在线程:UI线程     */    protected void onPostExecute(Result result) {    }    /**     * Runs on the UI thread after {@link #publishProgress} is invoked.     /** * 在publishProgress之后调用,用来更新计算进度 * 所在线程:UI线程     */    protected void onProgressUpdate(Progress... values) {    }     /** * cancel被调用并且doInBackground执行结束,会调用onCancelled,表示任务被取消 * 这个时候onPostExecute不会再被调用,二者是互斥的,分别表示任务取消和任务执行完成 * 所在线程:UI线程     */    @SuppressWarnings({UnusedParameters})    protected void onCancelled(Result result) {        onCancelled();    }            protected void onCancelled() {    }    public final boolean isCancelled() {        return mCancelled.get();    }    public final boolean cancel(boolean mayInterruptIfRunning) {        mCancelled.set(true);        return mFuture.cancel(mayInterruptIfRunning);    }    public final Result get() throws InterruptedException, ExecutionException {        return mFuture.get();    }    public final Result get(<a target=_blank href="http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=0&is_app=0&jk=ef0bb49edecdbe09&k=long&k0=long&kdi0=0&luki=6&mcpm=0&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=9becdde9eb40bef&ssp2=1&stid=9&t=tpclicked3_hc&td=1836545&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D577651%2Ehtml&urlid=0" target="_blank" style="padding: 0px; color: rgb(51, 136, 255); text-decoration: none;">long</a> timeout, TimeUnit unit) throws InterruptedException,            ExecutionException, TimeoutException {        return mFuture.get(timeout, unit);    }    /**     * 这个方法如何执行和系统版本有关,在AsyncTask的使用规则里已经说明,如果你真的想使用并行AsyncTask, * 也是可以的,只要稍作修改 * 必须在UI线程调用此方法     */    public final AsyncTask execute(Params... params) {//串行执行        return executeOnExecutor(sDefaultExecutor, params);//如果我们想并行执行,这样改就行了,当然这个方法我们没法改//return executeOnExecutor(THREAD_POOL_EXECUTOR, params);    }    /**     * 通过这个方法我们可以自定义AsyncTask的执行方式,串行or并行,甚至可以采用自己的Executor * 为了实现并行,我们可以在外部这么用AsyncTask: * asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, Params... params); * 必须在UI线程调用此方法     */    public final AsyncTask executeOnExecutor(Executor exec,            Params... params) {        if (mStatus != Status.PENDING) {            switch (mStatus) {                case RUNNING:                    throw <a target=_blank href="http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=0&is_app=0&jk=ef0bb49edecdbe09&k=new&k0=new&kdi0=0&luki=3&mcpm=0&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=9becdde9eb40bef&ssp2=1&stid=9&t=tpclicked3_hc&td=1836545&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D577651%2Ehtml&urlid=0" target="_blank" style="padding: 0px; color: rgb(51, 136, 255); text-decoration: none;">new</a> IllegalStateException(Cannot execute task:                            +  the task is already running.);                case FINISHED:                    throw <a target=_blank href="http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=0&is_app=0&jk=ef0bb49edecdbe09&k=new&k0=new&kdi0=0&luki=3&mcpm=0&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=9becdde9eb40bef&ssp2=1&stid=9&t=tpclicked3_hc&td=1836545&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D577651%2Ehtml&urlid=0" target="_blank" style="padding: 0px; color: rgb(51, 136, 255); text-decoration: none;">new</a> IllegalStateException(Cannot execute task:                            +  the task has already been executed                             + (a task can be executed only once));            }        }        mStatus = Status.RUNNING;//这里#onPreExecute会最先执行        onPreExecute();        mWorker.mParams = params;//然后后台计算#doInBackground才真正开始        exec.execute(mFuture);//接着会有#onProgressUpdate被调用,最后是#onPostExecute        return this;    }    /**     * 这是AsyncTask提供的一个静态方法,方便我们直接执行一个runnable     */    public static void execute(Runnable runnable) {        sDefaultExecutor.execute(runnable);    }    /** * 打印后台计算进度,onProgressUpdate会被调用     */    protected final void publishProgress(Progress... values) {        if (!isCancelled()) {            sHandler.obtainMessage(MESSAGE_POST_PROGRESS,                    <a target=_blank href="http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=0&is_app=0&jk=ef0bb49edecdbe09&k=new&k0=new&kdi0=0&luki=3&mcpm=0&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=9becdde9eb40bef&ssp2=1&stid=9&t=tpclicked3_hc&td=1836545&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D577651%2Ehtml&urlid=0" target="_blank" style="padding: 0px; color: rgb(51, 136, 255); text-decoration: none;">new</a> AsyncTaskResult(this, values)).sendToTarget();        }    }//任务结束的时候会进行判断,如果任务没有被取消,则onPostExecute会被调用    private void finish(Result result) {        if (isCancelled()) {            onCancelled(result);        } else {            onPostExecute(result);        }        mStatus = Status.FINISHED;    }//AsyncTask内部Handler,用来发送后台计算进度更新消息和计算完成消息    private static class InternalHandler extends Handler {        @SuppressWarnings({unchecked, RawUseOfParameterizedType})        @Override        public void handleMessage(Message msg) {            AsyncTaskResult result = (AsyncTaskResult) msg.obj;            <a target=_blank href="http://cpro.baidu.com/cpro/ui/uijs.php?adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=0&is_app=0&jk=ef0bb49edecdbe09&k=switch&k0=switch&kdi0=0&luki=8&mcpm=0&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=9becdde9eb40bef&ssp2=1&stid=9&t=tpclicked3_hc&td=1836545&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D577651%2Ehtml&urlid=0" target="_blank" style="padding: 0px; color: rgb(51, 136, 255); text-decoration: none;">switch</a> (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;            }        }    }    private static abstract class WorkerRunnable implements Callable {        Params[] mParams;    }    @SuppressWarnings({RawUseOfParameterizedType})    private static class AsyncTaskResult {        final AsyncTask mTask;        final Data[] mData;        AsyncTaskResult(AsyncTask task, Data... data) {            mTask = task;            mData = data;        }    }}
1 0
原创粉丝点击