介绍和注意事项
AsyncTask
是异步处理数据的类,相当于Thread+Handler的封装,内部维护了线程池ThreadPoolExecutor,主要有4个方法,onPreExecute() doInBackground() onProgressUpdate() onPostExecute(),执行顺序也是这么排列的,只有doInBackground()是必须要实现的,因为它是由abstrct修饰。
AsyncTask的执行必须在UI线程,因为其内部维护了Handler,而handleMessage()处理消息必须在UI线程。
AsyncTask只能执行一次,执行多次会抛出异常
java.lang.IllegalStateException: Cannot execute task: the task is already running.
如连续2次调用execute()就会报错。
task.execute();
task.execute();
内部方法介绍
这4个方法中,也只有doInBackground()方法是在子线程中执行的,其余3个都是在UI线程。
4个方法执行是有先后顺序的,而且是自动执行的,不需要使用对象调用这些方法。
另外还有2个方法:onCancelled(String s) onCancelled(),在task取消的时候调用(task.cancel(true))
- onPreExecute()
task执行前调用,比如设置progress的最大值和初始化值。在UI线程执行 - doInBackground()
执行具体的任务,在子线程中执行,通过pulishProgress()发送任务进度值 - onProgressUpdate()
接受pulishProgress()发送的进度值。在UI线程执行 - onPostExecute()
任务执行结束后调用该方法。在UI线程执行
其中onProgressUpdate(Integer... values)
参数是Array,一般只取第一个值:values[0]
判断各方法是否在主线程中执行?
在各方法中打印出当前Thread的name
Thread.currentThread().getName()
AsyncTask<String, Integer, String> task = new AsyncTask<String, Integer, String>() {
@Override
protected String doInBackground(String... params) {
LogUtil.d("doInBackground:" + Thread.currentThread().getName());
return null;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
LogUtil.d("onPreExecute:" + Thread.currentThread().getName());
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
LogUtil.d("onPostExecute:" + Thread.currentThread().getName());
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
LogUtil.d("onProgressUpdate:" + Thread.currentThread().getName());
}
@Override
protected void onCancelled(String s) {
super.onCancelled(s);
LogUtil.d("onCancelled:" + Thread.currentThread().getName());
}
@Override
protected void onCancelled() {
super.onCancelled();
LogUtil.d("onCancelled:" + Thread.currentThread().getName());
}
}.execute();
AsyncTask缺陷
- 生命周期不好控制
AsyncTask生命周期方法要么自己走完,要么调用cancle()取消task。由于AsyncTask是对Thread和Handler的封装,thread是不好控制的。当Activity被销毁的时候,应该让AsyncTask取消这个任务,但是它的doInBackGround()可能没有执行完,那么走到onPostExecute()时更新ui,会发现view=null,报错 - 容易引起内存泄露
如果在Activity内部生命一个AsyncTask内部类,由于AsyncTask的生命周期比较长,当Activity被销毁的时候,AsyncTask没走完,还持有该Acitivity的引用,导致Actiivty无法被回收,引起内存泄露。 - 数据丢失
横竖屏切换的时候,AsyncTask持有的Activity的引用就无效了,无法更新ui。