AsyncTask是一个专门用来处理后台进程与UI线程的工具。AsyncTask背后的实现原理是基于异步消息处理机制的,这个类主要是为耗时操作开辟一个新线程,基于此类可以实现UI线程和后台线程间的通讯,后台线程执行异步任务,并把结果返回给UI线程。
AsyncTask是一个轻量级的异步任务类,它可以在线程池中执行后台任务,然后把执行的进度和最终的结果传递给主线程并在主线程中更新UI。从实现上来说,AsyncTask封装了Thread和Handler,通过AsyncTask可以更加方便地执行后台任务以及在主线程中访问UI,但是AsyncTask并不适合进行特别耗时地后台任务,对于特别耗时的任务来说,建议使用线程池。
由于AsyncTask是一个抽象类(即使用时需要实现子类),所以我们想使用它必须创建一个子类去继承它。在继承时需要指定3个泛型参数:
(1)Params,在执行AsyncTask时需要传入的参数,可用于在后台任务中使用。
(2)Progress,后台任务执行时,如果需要在界面上显示当前的进度,则使用这里指定的泛型作为进度单位。
(3)Result,当任务执行完毕后,如果需要对结果进行返回,则使用这里指定的泛型作为返回值类型。
因此,一个简单的自定义AsyncTask就可以写成如下方法:
class a extends AsyncTask<Void, Integer, Boolean>(
//将第一个泛型参数设置为Void,表示在执行时不需要传入参数给后台任务。
//将第二个泛型参数设置为Integer,表示使用整型数据来作为进度显示单位。
//将第三个泛型参数设置为Boolean,表示使用布尔数据来反馈执行结果。
)
AsyncTask有4个重要的回调方法:
(1)onPreExecute(),onPreExecute运行在UI线程,主要目的是为后台线程的运行做准备。当它运行完后,会调用doInBackground方法。(这个方法会在后台任务开始执行之前调用,用于进行一些界面上的初始化操作。)
(2)doInBackground(Params…),doInBackground运行在后台线程,用来负责运行任务,它拥有参数params,并且返回Result。在后台线程的运行当中,为了能够更新作业完成的进度,需要在doInBackground方法中调用publishProgress方法。该方法拥有参数params,通过该方法可以更新progress数据,然后当调用完publishProgress方法,它会调用onProgressUpdate方法用于更新进度。(这个方法中的所有代码都会在子线程中运行,我们应该在这里去处理所有的耗时任务。注意,在这个方法是不可以进行UI操作的,如果需要更新UI元素,比如说反馈当前任务的执行进度,可以调用publishProgress(Progress…)方法来完成)
(3)onProgressUpdate(Progress…),onProgressUpdate运行在UI线程,主要目的是用来更新UI线程中显示进度的UI控制。它拥有Progress参数,在doInBackground中调用PublishProgress之后,就会自动调onProgressUpdate方法。(在这个方法中可以对UI进行操作,利用参数中的数值就可以对界面元素进行相应的更新。)
(4)onPostExecute(Result),onPostExecute运行在UI线程,当doInBackground方法运行完后,它会调用onPostExecute方法,并传入Result。在onPostExecute方法中,就可以将Result更新到UI控件上。(当后台任务执行完毕并通过return语句进行返回时,这个方法就很快会被调用。返回的数据会作为参数传递到此方法中,可以利用返回的数据来进行一些UI操作。)
简单来说,使用AsyncTask的诀窍就是,在doInBackground()方法中执行具体的耗时任务,在onProgressUpdate()方法中进行UI操作,在onPostExecute()方法中执行一些任务的收尾工作。
一个比较完整的自定义AsyncTask就可以写成如下方式:
class MyAsyncTask extends AsyncTask<String, Void, Boolean>(){
@Override
protected Boolean doInBackground(Void... params){
return null;
}
@Override
protected void onPreExecute(){
super.onPreExecute();
}
@Override
protected void onPostExecute(Boolean result){
super.onPostExecute(result);
}
@Override
protected void onProgressUpdate(Integer...values){
super.onProgressUpdate(values);
}
}
//注:doInBackground和onProgressUpdate方法的参数中均包含...的字样
//在Java中...表示参数的数量不定,它是一种数组型参数。
AsyncTask的使用:
1、创建一个子类继承AsyncTask
2、在子类中实现如下方法:
①onPreExecute()
②doInBackground()
③onProgressUpdate()
④onPostExecute()
3、调用execute方法,如下所示:
new MyAsyncTask().execute();
简单来说,使用AsyncTask的基本用法是:在doInBackground()方法中执行具体的耗时任务,在onProgressUpdate()方法中进行UI操作,在onPostExecute()方法中执行一些任务的收尾工作。
1、AsyncTask的类必须在主线程中加载。
2、必须在UI线程中创建AsyncTask的实例(对象)。
3、必须在UI线程中调用AsyncTask的execute方法。
4、AsyncTask被重写的四个方法是系统自动调用的,不应手动调用。不要在程序中直接调用onPreExecute()、onPostExecute()、doInBackground()和onProgressUpdate()方法。
5、每个AsyncTask只能被执行(execute方法)一次,多次执行将会引发异常。因此,每次使用时,都需要创建一个子类。
5、AsyncTask的四个方法,只有doInBackground方法是运行在其他线程中,其他三个方法都运行在UI线程中,也就说其他三个方法都可以进行UI的更新操作。
6、生命周期不受Activity约束,可能会造成内存泄漏。
原因:在Activity中使用AsyncTask,AsyncTask持有Activity的引用,如果在网络请求没有结束,但是Activity已经被关闭的情况下,Activity的引用得不到释放,就会造成内存泄漏。
解决方法:
①将AsyncTask设置为static,设置为静态对象后,在Activity类初始化的时候会初始化,会占用一定的内存,但是会和Activity同生命周期,Activity销毁时AsyncTask也会被销毁。
②使用弱引用,这样gc运行时就会回收,避免内存泄漏。