AsyncTask原理
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AsyncTask原理相关的知识,希望对你有一定的参考价值。
1、对于耗时的操作(如上传下载、读写数据库等),为了不阻塞主线程,我们的一般方法是开启“子线程”。如果需要更新UI,则需要使用handler
2、如果耗时的操作太多,那么我们需要开启太多的子线程,这就会给系统带来巨大的负担,随之也会带来性能方面的问题。在这种情况下我们就可以考虑使用类AsyncTask来异步执行任务,不需要子线程和handler,就可以完成异步操作和刷新UI。
3、AsyncTask的构造方法有三个模板参数
Params(传递给后台任务的参数类型)
Progress(后台计算执行过程中,进度单位(progress units)的类型,也就是后台程序已经执行了百分之几)
Result(后台执行返回的结果的类型)。
4、AsyncTask:对线程间的通讯做了轻量级的包装,代码上较之handler更为轻量(实际更耗资源),使用它后台线程和UI线程可以简易通讯:后台线程执行异步任务,将result告知UI线程。
AsyncTask本质上是一个静态的线程池,由它派生出来的子类可以实现不同的异步任务,但这些任务都是提交到该静态线程池中执行,执行的时候通过调用doInBackground()方法执行异步任务,期间会通过Handler将相关的信息发送到UI线程中,但神奇的是,并不是调用UI线程中的回调方法,而是AsyncTask本身就有一个Handler的子类InternalHandler会响应这些消息并调用AsyncTask中相应的回调方法。从上面的代码中我们也可以看到,UI的ProgressBar的更新是在AsyncTask的onProgressUpdate(),而ImageView是在onPostExecute()方法里。这是因为InternalHandler其实是在UI线程里面创建的,所以它能够调用相应的回调方法来更新UI。
AsyncTask就是专门用来处理后台任务的,而且它针对后台任务的五种状态提供了五个相应的回调接口,使得我们处理后台任务变得非常方便。
如果只是普通的UI更新操作,像是不断更新TextView这种动态的操作,可以使用Handler,但如果是涉及到后台操作,像是下载任务,然后根据后台任务的进展来更新UI,就得使用AsyncTask,但如果前者我们就使用AsyncTask,那真的是太大材小用了!!
5、两组成部分
一个是与主线各的交互,另一个就是线程的管理调度。虽然可能多个AsyncTask的子类的实例,但是AsyncTask的内部Handler和ThreadPoolExecutor都是进程范围内共享的,其都是static的,也即属于类的,类的属性的作用范围是CLASSPATH,因为一个进程一个VM,所以是AsyncTask控制着进程范围内所有的子类实例。
6、使用方法
自定义AsyncTask,在耗时的地方调用自定义的AsyncTask。可以参照以下代码示例。
step1:继承AsyncTask<Params,Progress,Result>
Params:输入参数。对应的是调用自定义的AsyncTask的类中调用excute()方法中传递的参数。如果不需要传递参数,则直接设为Void即可。
Progress:子线程执行的百分比
Result:返回值类型。和doInBackground()方法的返回值类型保持一致。
step2:实现以下几个方法:执行时机和作用看示例代码,以下对返回值类型和参数进行说明
onPreExecute():无返回值类型。不传参数
doInBackground(Params... params):返回值类型和Result保持一致。参数:若无就传递Void;若有,就可用Params
publishProgress(Params... params):在执行此方法的时候会直接调用onProgressUpdate(Params... values)
onProgressUpdate(Params... values):无返回值类型。参数:若无就传递Void;若有,就可用Progress
onPostExecute(Result result) :无返回值类型。参数:和Result保持一致。
step3:在调用自定义的AsyncTask类中生成对象;
执行 :对象.excute(Params... params);
7、基本使用
protected void onPreExecute()
protected abstract Result doInBackground(Params... params)
protected void onPostExecute(Result result)
protected void onProgressUpdate(Progress... values)
8、源码分析
private static final int CORE_POOL_SIZE = 5; //核心线程数
private static final int MAXIMUM_POOL_SIZE = 128; //最大线程数
private static final int KEEP_ALIVE = 1; //超时时间,当线程数超过核心线程数时,超过这个时间的空线程就会被销毁,直到线程数等于核心线程
9、缺陷
9.1 同时只有5个线程去访问网络-->这个是重点
9.2 线程数目超过128,会抛异常RejectedExecutionException-->这个情况其实还好;
解决方法:由一个控制线程来处理AsyncTask的调用判断线程池是否满了,如果满了则线程睡眠否则请求AsyncTask继续处理。
10、版本差异(线程的管理调度方面)
AsyncTask的线程管理调度:内部会创建一个进程作用域的线程池来管理要运行的任务,也就就是说当你调用了AsyncTask#execute()后,AsyncTask会把任务交给线程池,由线程池来管理创建Thread和运行Therad。
10.1 CORE_POOL_SIZE MAXIMUM_POOL_SIZE KEEP_ALIVE在不同的版本上.值是不一样;
10.2 1.5前是串行执行的.每次执行1个任务
10.3 1.6-2.3(API4-10)的版本.是并行执行的.每次执行5个任务
10.4 3.0后提供串行和并行,默认情况是串行
executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, null);//串行
executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, null);//并行
11、简单封装
> 实际开发我们会去继承Asynctask
12、与handler相比
12.1 AsyncTask
优点:简单快捷,过程可控、易于维护;
缺点:在使用多个异步操作和并需要进行Ui变更时,就变得复杂起来
12.2 handler
优点:结构清晰,功能定义明确;对于多个后台任务时,简单,清晰
缺点:在单个后台异步处理时,显得代码过多,结构过于复杂(相对性)
12.3 AsyncTask是对Thread+Handler良好的封装,在android.os.AsyncTask代码里仍然可以看到Thread和Handler的踪迹
12.4 AsyncTask底层是一个线程池,而handler底层是一个消息队列(可以不开启线程),所以AsyncTask虽然有着更为轻量级的代码,但较之handler更耗资源
13、小结
13.1 Task的实例必须在UI thread中创建
13.2 execute方法必须在UI thread中调用
13.3 不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground=\\‘#\\‘" onProgressUpdate(Progress...)这几个方法
13.4 该task只能被执行一次,否则多次调用时将会出现异常
13.5 数据简单使用AsyncTask:实现代码简单;
数据量多且复杂使用handler+thread:相比较AsyncTask来说能更好的利用系统资源且高效
http://www.cnblogs.com/suinuaner/archive/2013/04/11/android_fifty.html
http://www.cnblogs.com/wenjiang/p/3180324.html
http://blog.csdn.net/hitlion2008/article/details/7983449
以上是关于AsyncTask原理的主要内容,如果未能解决你的问题,请参考以下文章