1.为什么要使用?
在Android程序开始运行的时候会单独启动一个进程,默认情况下所有这个程序操作都在这个进程中进行。一个Android程序默认情况下只有一个进程,但是一个进程却是可以有许线程的。在这些线程中,有一个线程叫做UI线程,也叫做Main Thread,除了Main Thread之外的线程都可称为Worker Thread。Main Thread主要负责控制UI页面的显示、更新、交互等。Main Thread不能进行耗时操作,否则会ANR或程序卡顿。
2.应用场景
例如网络请求、数据库操作、复杂计算等逻辑都封装到单独的线程
3.使用
AsyncTask是一个抽象类,我们在使用时需要定义一个它的派生类并重写相关方法。AsyncTask类的声明如下:
public abstract class AsyncTask<Params, Progress, Result>
我们可以看到,AsyncTask是一个泛型类,它的三个类型参数的含义如下:
- Params:doInBackground方法的参数类型;
- Progress:AsyncTask所执行的后台任务的进度类型;
- Result:后台任务的返回结果类型。
我们再来看一下AsyncTask类主要为我们提供了哪些方法:
onPreExecute() //此方法会在后台任务执行前被调用,用于进行一些准备工作 doInBackground(Params... params) //此方法中定义要执行的后台任务,在这个方法中可以调用publishProgress来更新任务进度(publishProgress内部会调用onProgressUpdate方法) onProgressUpdate(Progress... values) //由publishProgress内部调用,表示任务进度更新 onPostExecute(Result result) //后台任务执行完毕后,此方法会被调用,参数即为后台任务的返回结果 onCancelled() //此方法会在后台任务被取消时被调用
以上方法中,除了doInBackground方法由AsyncTask内部线程池执行外,其余方法均在主线程中执行。
4、AsyncTask内部线程池
AnsycTask执行任务时,内部会创建一个线程池来管理要运行的任务,也就就是说当你调用了AsyncTask.execute()后,AsyncTask会把任务交给线程池,由线程池来管理创建Thread和运行Therad。
3.0之前规定同一时刻能够运行的线程数为5个,线程池总大小为128。
3.0之后默认execute()方法运行一个线程,但是可以使用executeOnExecutor(exec)同时运行多个线程
5.串行还是并行
newAsyncTask1().execute();
newAsyncTask2().execute();
如果两个任务同时执行为并行,从上到下为并行
3.0之后调用默认是串行的(顺序执行),executeOnExecutor()使用这个方法为并行
6.需要遵循的准则
a.task的实例必须在ui thread中创建
b.execute方法必须在ui thread中调用
c.不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法
d.该task只能被执行一次,否则多次调用时将会出现异常
7.使用的缺项
a.cancel()方法不能很好使用
当调用cancel(false),doInBackground()仍然会执行到方法结束,只是不会去调用onPostExecute()方法,这样相当于无效操作
当调用cancel(true),doInBackground()有不可打断的方法会失效。
b.内存泄露
在Activity中使用非静态匿名内部AsyncTask类,由于Java内部类的特点,AsyncTask内部类会持有外部类的隐式引用。如果AsyncTask进行耗时操作,当activity进行销毁操作时,由于持有引用,导致activity无法被回收.
c.结果丢失
另一个问题就是在屏幕旋转等造成Activity重新创建时AsyncTask数据丢失的问题。当Activity销毁并创新创建后,还在运行的AsyncTask会持有一个Activity的非法引用即之前的Activity实例。导致onPostExecute()没有任何作用。