android UI是线程不安全的,所以想实如今子线程中刷新UI就须要借助一些机制来实现,通常有两种方法:handler+message;还有一种就是今天咱们要讲的asyncTask。asyncTask相对handler+message要轻量级一些。java
asyncTask是一个抽象类,所以咱们须要自定义一个类来继承他,而且实现他的方法。android
asyncTask指定了三个泛型参数,其中Params是可变长的泛型参数,三个参数用法以下:web
Params:asyncTask传入的参数可在后台执行任务时使用数据库
Progress:后台执行任务时,若是须要在前台显示进度,这里是指定泛型做为进度单位缓存
Result:后台执行任务完成,若是须要返回结果到前台,这里是指定泛型做为返回值类型安全
除了参数下面介绍下咱们常常须要重写的四个方法:多线程
onPreExecute():在任务执行以前调用,进行一些初始化操做,好比显示一个进度条,这个方法是在主线程运行的。并发
doInBackground(Void... arg0):这个方法是用来执行耗时操做的,把你想要异步处理的任务的代码放在这里面,这个确定是在子线程执行的。因此这个方法里面不能进行UI操做,若是想要更新UI的话,好比更新进度能够调用publishProgress(values)方法。异步
onProgressUpdate(Integer... values):后台执行了publishProgress(values);方法后处过来的值就能够用来更新前台的进度了,可见这个是在主线程执行的。async
onPostExecute(Boolean result):后台任务执行完毕返回结果的时候会调用这个方法,将结果返回给主进程或者进行UI操做,可见也是在主进程进行的。
还有一个onCancelled()方法,当用户取消任务的时候调用。有两点须要注意的地方:
一、asyncTask的实例化操做和execute()方法调用必须在UI线程操做。
二、asyncTask只能被执行一次,不能重复执行。源码里有一个判断:若是任务正在运行或者是已经结束的任务重复调用会抛出异常。
下面咱们来自定义一个asyncTask:
public class MyAsyncTask extends AsyncTask<Void, Integer, Boolean>{ @Override protected void onPreExecute() { // TODO Auto-generated method stub super.onPreExecute(); } @Override protected Boolean doInBackground(Void... arg0) { // TODO Auto-generated method stub publishProgress(values); return null; } @Override protected void onProgressUpdate(Integer... values) { // TODO Auto-generated method stub super.onProgressUpdate(values); } @Override protected void onPostExecute(Boolean result) { // TODO Auto-generated method stub super.onPostExecute(result); } @Override protected void onCancelled() { // TODO Auto-generated method stub super.onCancelled(); } }
这里咱们把AsyncTask的第一个泛型参数指定为Void,表示在执行AsyncTask的时候不须要传入参数给后台任务,第二个泛型参数指定为Integer,表示使用整型数据来做为进度显示单位。第三个泛型参数指定为Boolean,表示子线程中返回的数据类型。
Android 3.0之前AsyncTask容许同时执行5个任务,线程池大小为128个,也就是说添加了10个任务,只有前五个在执行,等有一个执行完毕才会执行第六个,固然最多添加128个任务;3.0以后改为了只容许同时执行一个任务,为何变少了呢?3.0之后增长了他的灵活性,AsyncTask能够接受自定义线程池了。
public ExecutorService executorService = Executors.newFixedThreadPool(5); new MyAsyncTask().executeOnExecutor(executorService);
以上代码自定义了一个线程数为5的线程池,一样是能够执行5个任务。
说道线程池,之前还真没接触过,只是用用别人封装好了的罢了。正好遇到了,也就了解一下,毕竟技不压身,哈哈哈...
先来看下ExecutorService,ExecutorService是线程池的一个服务,能够随时关闭线程池,它里面有几个经常使用的线程池对象:
newCachedThreadPool()
它是一个缓存型的池子,须要建立线程的时候他会先查看有没有之前建立过的,若是有就回收,没有才会从新建立。适合执行一些生命周期较短的异步任务,它里面的线程都有一个time out限制,也就是说若是一个线程超过60s没有活动,那么这个线程将被移除。固然前面说的回收,确定是回收的没有time out 的线程。因此放入它里面的线程没必要担忧它的结束,超过60S不活动,会自动终止。
newFixedThreadPool(count)
这个线程池跟cache池相似,它也能够回收前面的线程,可是它的特殊之处在于同一时间它只容许固定数目的线程活动,实例化的时候能够限定一个线程数目,好比上面提到的5个线程同步执行,固然也能够根据CPU个数来动态设定线程个数,最好设置成核数的2N以下代码:
int count = Runtime.getRuntime().availableProcessors() ; ExecutorService executorService = Executors.newFixedThreadPool(count*2);
若是指定了线程数目,在手机性能较差的状况下可能会发生卡顿,ANR现象。fixed池子里面的线程应该没有time out或者是时间很长,基本不会超时。
newScheduledThreadPool(count)
能够实现一个定长的可延时或者周期执行的线程池;
newSingleThreadExceoutor()
能够实现一个只容许一个工做线程工做的线程池。这个池子里面只容许一个线程在活动,顺序完成全部的任务。能够用于数据库的操做,文件操做,或者是批量安装应用,卸载应用等不适合高并发但有可能IO阻塞以及影响UI相应的操做。
关于多线程就讲到这里,只是讲了一点基础知识,想要深刻了解的能够自行百度。