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;
}
}
}
Android Asynctask与Handler的比较,优缺点区别,Asynctask源码的更多相关文章
- Android菜鸟的成长笔记(6)——剖析源码学自定义主题Theme
原文:Android菜鸟的成长笔记(6)--剖析源码学自定义主题Theme 还记得在Android菜鸟的成长笔记(3)中我们曾经遇到了一个问题吗?"这个界面和真真的QQ界面还有点不同的就是上 ...
- Android中Canvas绘图基础详解(附源码下载) (转)
Android中Canvas绘图基础详解(附源码下载) 原文链接 http://blog.csdn.net/iispring/article/details/49770651 AndroidCa ...
- Android Handler机制(一)---Message源码分析
Message: 定义: public final class Message implements Parcelable Message类是个final类,就是说不能被继承,同时Message类实现 ...
- Android Handler处理机制 ( 一 )(图+源码分析)——Handler,Message,Looper,MessageQueue
android的消息处理机制(图+源码分析)——Looper,Handler,Message 作为一个大三的预备程序员,我学习android的一大乐趣是可以通过源码学习 google大牛们的设计思想. ...
- Android(java)学习笔记203:网页源码查看器(Handler消息机制)
1.项目框架图: 2.首先是布局文件activity_main.xml: <LinearLayout xmlns:android="http://schemas.android.com ...
- Android(java)学习笔记146:网页源码查看器(Handler消息机制)
1.项目框架图: 2.首先是布局文件activity_main.xml: <LinearLayout xmlns:android="http://schemas.android.com ...
- Android事件分发详解(三)——ViewGroup的dispatchTouchEvent()源码学习
package cc.aa; import android.os.Environment; import android.view.MotionEvent; import android.view.V ...
- Android Studio使用Mob来获取手机验证码的源码
本文来自:CSDN 感谢作者:qq_35812301(其实就是我的号!) 查看原文:http://blog.csdn.net/qq_35812301/article/details/79150775 ...
- vue系列---理解Vue中的computed,watch,methods的区别及源码实现(六)
_ 阅读目录 一. 理解Vue中的computed用法 二:computed 和 methods的区别? 三:Vue中的watch的用法 四:computed的基本原理及源码实现 回到顶部 一. 理解 ...
- Android Studio 的蓝牙串口通信(附Demo源码下载)
根据相关代码制作了一个开源依赖包,将以下所有的代码进行打包,直接调用即可完成所有的操作.详细说明地址如下,如果觉得有用可以GIthub点个Star支持一下: 项目官网 Kotlin版本说明文档 Jav ...
随机推荐
- dubbo客户端源码分析(一)
rpc框架有很多,公司自研.开源的thrift.dubbo.grpc等.我用过几个框架,了解了一下实现原理,客户端基本都是用代理实现,jdk动态代理.cglib等.最近一段时间想了解一下dubbo源码 ...
- Java 时区转换(UTC+8 到 UTC 等等)
前言:需要做时区转换,知道北京为UTC+8,东京为UTC+9,世界标准时间为UTC,所以下面的代码是只需要知道时区是+8还是+9还是0就可以了,不需要使用"CTT". " ...
- csharp:FlowLayoutPanel
/// <summary> /// 集合添加的控件 /// 涂聚文20150339 /// </summary> public void AddNewTextBox() { P ...
- PoPo数据可视化周刊第一期
PoPo数据可视化 聚焦于Web数据可视化领域, 发现前端可视化领域有意思的内容. 涵盖前端可视化领域最新资讯, 开源可视化库的发布更新消息, 可视化案例分析与讲解, 可视化技术文章, 可视化大神的日 ...
- bsgs(Baby Steps Giant Steps)算法
BSGS算法(Baby Steps Giant Steps算法,大步小步算法,北上广深算法,拔山盖世算法) 适用问题 对于式子: $$x^y=z(mod_p)$$ 已知x,z,p,p为质数: 求解一个 ...
- Linux菜鸟简单命令
想要使用Linux,以下这些命令不可少的哦! 我在工作中经常用到的大多数都是一些文件的查找,和上传下载什么的,没什么技术含量,所以除了自己整理的之外,还有借鉴的别的大神的一些命令,我会在最后标注的\( ...
- iOS各种profile文件
iOS是一个非常封闭的系统.授权文件(.mobileprovision)和签名证书文件(.cer)的存在就是为了验证身份信息.一般情况下,比如ssh登陆或者scp需要私钥.公钥对即可,iOS也是基本采 ...
- 移动端App开发 - 02 - iPhone/iPad/Android UI尺寸规范
移动端app开发 - iPhone/iPad/Android UI尺寸规范 本笔记抛去无用的前期分析什么的,全是干货,简洁干练 本笔记不单独针对 ios 或者 Android,两种都介绍,当然我们实际 ...
- 【转】pscp实现远程文件(夹)传输
原文地址:http://blog.163.com/yang_jianli/blog/static/16199000620128251383197/ pscp与linux下的scp命令相似,功能相同,在 ...
- js脚本快速评课----中科大教务系统
git地址:https://github.com/hzphzp/js_ustc_mis_teach 代码 for(var i = 1; i < document.getElementsByTag ...