什么是异步任务?
异步任务就是开一个子线程,然后让它去跑,它跑完了就会回来告诉你说,它跑完了,这是结果。这和Java中的回调差不多。我们在OKHttp中很长见到的 onSuccess() 和 onError() 这些都是回调函数。当然这篇博文不讨论这些回调,只讨论Android中自带的异步任务。
Android官方在4.0以后的版本系统里面就禁止在主线程访问网络了。
解决这个的唯一的办法就是开一个子线程,子线程去访问网络。刚好,google 给 Android 写了一个方便广大各位编程人员使用的工具类,AsyncTask。下面就来看看这个异步任务怎么用?
首先,写一个类,继承 AsyncTask,实现 AsyncTask 比较简单,必须实现的只有一个方法,那就是doInBackground() 其他都可以不需要去实现的,但通常我们使用的时候都不仅仅是重写 doInBackground() 还有其他函数与之相配合。下面就来看看这几个函数分别是什么,各自有什么作用。
doInBackground()
这方法是在子线程中执行的,也是里面这么多方法中唯一一个是子线程中执行的,这里一般做的是异步任务要做的事情(也就是耗时的任务),例如访问网络等,都写在这个方法里面。
onPreExecute()
这个方法是在UI线程中执行的,看方法名也知道个大概了,这个方法是在 doInBackground() 之前调用,也就是异步任务的准备工作等,例如:访问网络前弹出进度条,收集要传递的参数等等。。。
onPostExecute()
这个和前面的 onPreExecute() 相对应。它是在 doInBackground() 之后执行的,同时也是在UI线程中执行的。这里一般用来做异步任务执行完毕后的操作,例如,Json解析(有些JSON大一点的也会在doInbackground()解析),更新列表,UI上的文字图片等等。。。
onProgressUpdate()
既然有前有后了,那么就差一个中间的了。没错,这个方法就是在 doInBackground() 执行的过程中回调的一个方法。这个有什么用呢?存在就是有道理的,例如我们下载的时候一般都会告诉你下载了百分之多少,对吧。还有,这个函数也是在UI线程中执行的。
另外还有其他的几个函数 onCancel() 等,这些都不怎么常用,可以稍做理解就可以。没必要深入的去看。
泛型和方法的返回值、参数是啥意思?
函数搞懂什么作用的了,仔细看看,我上面的都没有参数的,实际上是有参数的,对,是有,而且参数很重要。而且,我们继承 AsyncTask 的时候还有 3 个泛型的参数,这又是什么?现在就来看看泛型的参数和方法的参数以及方法的返回值分别是什么意思,并且分别有什么联系?
三个泛型分别是:Params, Progress, Result
Params:故名思议,是参数,也就是外部传递进来的参数,也就是我们执行execute()这个方法传递进来的,同时,可以看到,我们这个泛型和 doInBackground() 所接受的参数的类型是一致的。
Progress:这个参数也很好理解,就是进度,也就是执行过程回调的,我们可以看到 onProgressUpdate() 接收的参数的类型和这个是一致的,没错。就是这样
Result:这个参数也知道什么意思了,结果,也就是子线程的执行的结果,也是 doInBackground() 的返回值的类型,同时也是 onPostExecute() 所接收的参数的类型。
下面来看看参数之间的关系:
先看红色的箭头,红色的箭头表示规定的参数的类型的限制,也就是继承AsyncTask的时候的这 3 个参数类型其实限制的是 doInBackground 、 onProgressUpdate 、onPostExecute 这三个函数的接收的参数的类型和返回值的类型。
再看绿色的箭头,绿色的箭头表示数据的传递的过程。从一开始的execute的时候传递的参数,其实是传递到 doInBackground 里面的,doInBackground 返回的参数,其实是传递到 onPostExecute 。
以上两点是必须要搞清楚的,也是初学者比较难理解的,至于可变参数,初学者可以直接理解成数组,例如 doInBackground 接收的是 String... 你就可以理解成 String[] ,而取值的时候也是以数组的方式进行取值,更多可变参数的内容点击这里。
下面我们来通过一个例子来看看实际怎么使用?
代码没什么,就是通过日志去跟踪整个 AsyncTask 的执行的过程。
下面来看看 AsyncTask 的使用和打印的日志:
使用的话,这里直接就 new 了一个异步任务,然后直接调用 execute() 去执行了。
最后来分析分析日志,
onPreExecute() 确实是在 doInBackground() 之前执行,同时我们看传递进去的参数,传递进去的参数,分别是 “123” 、“456”,这里也分别取出来了。然后是执行子线程里面的代码,代码很简单,每休眠 1 秒就往 onProgressUpdate() 发送一次数据,这也可以通过日志看到,每次接收到的参数也分别打印出来,和我们发出去的参数是一致的。最后执行完了,执行完了返回的是 “true”,日志最后一行打印出来的也是true,这也证实了我们前面图上绿色箭头,参数的传递的过程。
整个 AsyncTask 到此解析完毕,下面还有几点需要说明的。
1、AsyncTask只能执行一次,不能执行多次。
2、一旦执行,不可取消,网上说的可以取消的都是骗子,都是骗子,不能取消,解决的唯一途径就是对这次请求的数据不做处理,也就是忽略数据,当作这次没请求,这就需要搞一个标志位去记住是否处理请求回来的数据。