zoukankan      html  css  js  c++  java
  • Android Asynctask与Handler的比较,优缺点区别,Asynctask源码

    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 = new HashMap<String, Activity>();//缓存activity集合
    	private static ExecutorService exec = Executors.newSingleThreadExecutor();
    	
    	@Override
    	public void onStart(Intent intent, int startId) {
    		super.onStart(intent, startId);
    		MainAsyncTask asyncTask = new MainAsyncTask();
    		//asyncTask.execute(task);
    		//asyncTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, task);
    		//asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, task);
    		//asyncTask.executeOnExecutor(Executors.newFixedThreadPool(2), task);
    		asyncTask.executeOnExecutor(exec, task);
    	}
    
    	private final class MainAsyncTask extends AsyncTask<Object, Integer, Object>{
    		private Task task;
    		@Override
    		protected Object doInBackground(Object... params) {
    			Object result = null;
    			task = (Task)params[0];
    			switch (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;
    		}
    
    		@Override
    		protected void onPostExecute(Object result) {
    			super.onPostExecute(result);
    			ActivityInterFace aif;
    			switch (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(new 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);
    	}
    
    	@Override
    	public 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();只有一个线程在执行任务

    package com.example.ztestandroid;
    import java.util.Calendar;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    import android.app.Activity;
    import android.os.AsyncTask;
    import android.os.Bundle;
    
    import com.example.ztestandroid.bean.Task;
    
    public class MainActivity extends  Activity {
    	 private static ExecutorService exec = Executors.newSingleThreadExecutor();  
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.activity_main);
    		System.out.println("start time: "+Calendar.SECOND);
    		for (int i = 1; i < 10; i++) {
    			int count  = i%2==0?1:2;
    			Task task = new Task(count, "task "+i);
    			MainAsyncTask asyncTask = new MainAsyncTask();
    			/*
    			 * 顺序执行,AsyncTask里面有5个核心线程,最大128个
    			 * 01-14 11:30:47.000: I/System.out(17418): start time: 13
    			01-14 11:30:47.000: I/System.out(17418): end time: 13
    			01-14 11:30:47.000: I/System.out(17418): 任务2 task 1 Thread id: 840 seconds: 1421206247008
    			01-14 11:30:50.020: I/System.out(17418): 任务1 task 2 Thread id: 841 seconds: 1421206250028
    			01-14 11:30:50.025: I/System.out(17418): 任务2 task 3 Thread id: 842 seconds: 1421206250033
    			01-14 11:30:53.030: I/System.out(17418): 任务1 task 4 Thread id: 843 seconds: 1421206253037
    			01-14 11:30:53.040: I/System.out(17418): 任务2 task 5 Thread id: 844 seconds: 1421206253047
    			01-14 11:30:56.050: I/System.out(17418): 任务1 task 6 Thread id: 844 seconds: 1421206256053
    			01-14 11:30:56.050: I/System.out(17418): 任务2 task 7 Thread id: 844 seconds: 1421206256055
    			01-14 11:30:59.050: I/System.out(17418): 任务1 task 8 Thread id: 844 seconds: 1421206259057
    			01-14 11:30:59.050: I/System.out(17418): 任务2 task 9 Thread id: 844 seconds: 1421206259058
    			 */
    //	        asyncTask.execute(task);  
    	        // 和asyncTask.execute(task)执行结果相同,顺序执行。
    //			asyncTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, task); 
    			/*
    			 * 可以看出是异步执行,线程池里面最多有5个线程
    			 * 01-14 11:43:14.115: I/System.out(18208): start time: 13
    			01-14 11:43:14.115: I/System.out(18208): end time: 13
    			01-14 11:43:14.115: I/System.out(18208): 任务2 task 1 Thread id: 880 seconds: 1421206994121
    			01-14 11:43:14.115: I/System.out(18208): 任务2 task 3 Thread id: 877 seconds: 1421206994122
    			01-14 11:43:14.115: I/System.out(18208): 任务2 task 5 Thread id: 876 seconds: 1421206994122
    			01-14 11:43:14.115: I/System.out(18208): 任务2 task 7 Thread id: 877 seconds: 1421206994123
    			01-14 11:43:14.115: I/System.out(18208): 任务2 task 9 Thread id: 877 seconds: 1421206994123
    			
    			01-14 11:43:17.115: I/System.out(18208): 任务1 task 2 Thread id: 880 seconds: 1421206997122
    			01-14 11:43:17.115: I/System.out(18208): 任务1 task 6 Thread id: 878 seconds: 1421206997123
    			01-14 11:43:17.115: I/System.out(18208): 任务1 task 8 Thread id: 876 seconds: 1421206997123
    			01-14 11:43:17.115: I/System.out(18208): 任务1 task 4 Thread id: 879 seconds: 1421206997123
    			 */
    	        asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, task);  
    			
    			/*
    			 * 异步执行
    			 * 01-14 11:28:06.915: I/System.out(17143): start time: 13
    			01-14 11:28:06.915: I/System.out(17143): 任务2 task 1 Thread id: 837 seconds: 1421206086924
    			01-14 11:28:06.920: I/System.out(17143): 任务2 task 3 Thread id: 839 seconds: 1421206086925
    			01-14 11:28:06.920: I/System.out(17143): 任务2 task 5 Thread id: 841 seconds: 1421206086926
    			01-14 11:28:06.920: I/System.out(17143): 任务2 task 7 Thread id: 843 seconds: 1421206086926
    			01-14 11:28:06.920: I/System.out(17143): end time: 13
    			01-14 11:28:06.920: I/System.out(17143): 任务2 task 9 Thread id: 845 seconds: 1421206086927
    			01-14 11:28:09.925: I/System.out(17143): 任务1 task 2 Thread id: 838 seconds: 1421206089926
    			01-14 11:28:09.925: I/System.out(17143): 任务1 task 4 Thread id: 840 seconds: 1421206089927
    			01-14 11:28:09.925: I/System.out(17143): 任务1 task 6 Thread id: 842 seconds: 1421206089927
    			01-14 11:28:09.925: I/System.out(17143): 任务1 task 8 Thread id: 844 seconds: 1421206089927
    			 */
    //			asyncTask.executeOnExecutor(Executors.newFixedThreadPool(2), task);  
    		    /*
    		     * 执行结果:
    		     *   任务1 task 2 Thread id: 816 seconds: 1421205791881
    				 任务2 task 3 Thread id: 816 seconds: 1421205791882
    				 任务1 task 4 Thread id: 816 seconds: 1421205794883
    				 任务2 task 5 Thread id: 816 seconds: 1421205794883
    				 任务1 task 6 Thread id: 816 seconds: 1421205797884
    				 任务2 task 7 Thread id: 816 seconds: 1421205797885
    				 任务1 task 8 Thread id: 816 seconds: 1421205800886
    				 任务2 task 9 Thread id: 816 seconds: 1421205800887
    		     */
    //			asyncTask.executeOnExecutor(exec, task);  	
    		}
    		System.out.println("end time: "+Calendar.SECOND);
    	}
     
    	private final class MainAsyncTask extends AsyncTask<Object, Integer, Object>{  
            private Task task;  
            @Override  
            protected Object doInBackground(Object... params) {  
                Object result = null;  
                task = (Task)params[0];  
                switch (task.getTaskID()) {  
                case Task.TASK_USER_LOGIN:  
                    try {  
                        Thread.sleep(3000);  
                        System.out.println("任务"+task.getTaskID()+" "+ task.getTask()+" Thread id: "+Thread.currentThread().getId()+" seconds: "+System.currentTimeMillis());  
                    } catch (InterruptedException e) {  
                        e.printStackTrace();  
                    }  
                    break;  
                case 2:  
                	 System.out.println("任务"+task.getTaskID()+" "+ task.getTask()+" Thread id: "+Thread.currentThread().getId()+" seconds: "+System.currentTimeMillis());  
                    break;  
                }  
                return result;  
            }  
            @Override  
            protected void onPostExecute(Object result) {  
                super.onPostExecute(result);  
            }  
        }  
    }
    


    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 线程工厂,通过工厂方法newThread来获取新线程
        private static final ThreadFactory sThreadFactory = new ThreadFactory() {
    		//原子整数,可以在超高并发下正常工作
            private final AtomicInteger mCount = new AtomicInteger(1);
    
            public Thread newThread(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
                = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                        TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
    
        /**
         * 静态串行任务执行器,其内部实现了串行控制,
    	 * 循环的取出一个个任务交给上述的并发线程池去执行
         */
        public static final Executor SERIAL_EXECUTOR = new 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 = new 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 = new AtomicBoolean();
    	//原子布尔型,支持高并发访问,标识任务是否被执行过
        private final AtomicBoolean mTaskInvoked = new AtomicBoolean();
    
    	/*串行执行器的实现,我们要好好看看,它是怎么把并行转为串行的
    	 *目前我们需要知道,asyncTask.execute(Params ...)实际上会调用
    	 *SerialExecutor的execute方法,这一点后面再说明。也就是说:当你的asyncTask执行的时候,
    	 *首先你的task会被加入到任务队列,然后排队,一个个执行
    	 */
        private static class SerialExecutor implements Executor {
    		//线性双向队列,用来存储所有的AsyncTask任务
            final ArrayDeque mTasks = new 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 new asynchronous task. This constructor must be invoked on the UI thread.
         */
        public AsyncTask() {
            mWorker = new WorkerRunnable() {
                public Result call() throws Exception {
                    mTaskInvoked.set(true);
    
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    //noinspection unchecked
                    return postResult(doInBackground(mParams));
                }
            };
    
            mFuture = new FutureTask(mWorker) {
                @Override
                protected void done() {
                    try {
                        postResultIfNotInvoked(get());
                    } catch (InterruptedException e) {
                        android.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,
                    new 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(long 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 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会最先执行
            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,
                        new 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;
                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;
                }
            }
        }
    
        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;
            }
        }
    }



  • 相关阅读:
    【每天都要看一下】
    【这里有别人的经验,也有好玩的发现】
    【WPF】Listbox模板内button点击选中当前listboxItem
    【WFP】弹出窗口不在win10 任务列表里显示的方法
    PSD路径转换为 WPF path 的data
    【WPF】Listbox内item的样式替换默认选中样式和鼠标滑过样式
    【WPF】ListBox1内嵌套ListBox2 2的滑轮滚动阻止1的滚动解决方法
    【C#】文本框拼音检索汉字
    【WPF】Datagrid显示最低下一跳
    【C#】绝对随机数
  • 原文地址:https://www.cnblogs.com/lbangel/p/4335855.html
Copyright © 2011-2022 走看看