asyncTask详解

浪尽此生 提交于 2020-03-01 06:35:54

介绍

android UI是线程不安全的,因此想实现在子线程中刷新UI就需要借助一些机制来实现,一般有两种方法:handler+message;还有一种就是今天我们要讲的asyncTask。asyncTask相对handler+message要轻量级一些。

基本用法

asyncTask是一个抽象类,因此我们需要自定义一个类来继承他,并且实现他的方法。

asyncTask指定了三个泛型参数,其中Params是可变长的泛型参数,三个参数用法如下:

Params:asyncTask传入的参数可在后台执行任务时使用

Progress:后台执行任务时,如果需要在前台显示进度,这里是指定泛型作为进度单位

Result:后台执行任务完成,如果需要返回结果到前台,这里是指定泛型作为返回值类型

除了参数下面介绍下我们经常需要重写的四个方法:

onPreExecute():在任务执行之前调用,进行一些初始化操作,比如显示一个进度条,这个方法是在主线程运行的。

doInBackground(Void... arg0):这个方法是用来执行耗时操作的,把你想要异步处理的任务的代码放在这里面,这个肯定是在子线程执行的。所以这个方法里面不能进行UI操作,如果想要更新UI的话,比如更新进度可以调用publishProgress(values)方法。

onProgressUpdate(Integer... values):后台执行了publishProgress(values);方法后处过来的值就可以用来更新前台的进度了,可见这个是在主线程执行的。

onPostExecute(Boolean result):后台任务执行完毕返回结果的时候会调用这个方法,将结果返回给主进程或者进行UI操作,可见也是在主进程进行的。

还有一个onCancelled()方法,当用户取消任务的时候调用。有两点需要注意的地方:

1、asyncTask的实例化操作和execute()方法调用必须在UI线程操作。

2、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相应的操作。

关于多线程就讲到这里,只是讲了一点基础知识,想要深入了解的可以自行百度。

 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!