AsyncTask-异步任务
顾名思义,异步任务是做用于多线程协作的一个对象。Android的线程分为主线程(UI线程)和工作线程两种,主线程用于呈现和更新UI,但是不便于处理耗时操作以防止给用户带来不友好的体验(例如,下载一个大文件,如果在主线程进行,那么主线程就可能会阻塞很长时间,不但会给用户带来困扰,还有可能会发生ANR问题),而工作线程则不能更新UI,但是执行耗时操作不会影响用户的体验,所以这时,我们使用异步任务就可以实现主线程与工作线程之间的协作通讯,以达到在不阻塞主线程的情况下,在工作线程执行耗时操作并将工作线程执行的结果在主线程呈现给用户。
异步任务是一个抽象类,当我们去new这个类的子类时,有几个比较重要的方法需要我们去实现。在new子类时,我们会发现,它的构造方法含有三个参数 <Params, Progress, Result>,这三个参数都是泛型,其中,Params是我们在execute(Params... params)方法中要传入的参数,同时也是doInBackground(Params... params)方法中要传入的参数;Progress是publishProgress(Progress... values)中要使用的参数;而Result则是doInBackground(Params... params)方法得返回值类型,同时它还是onPostExecute(Result result)中要用到的参数,下面我们具体说一下AsyncTask类中的几个重要方法。
doInBackground(Params... params)方法是其中必须要重写的方法,也是异步任务中最重要的一个方法,这个方法中的代码是执行在工作线程的。虽然我们自己并没有去手动开一个工作线程,但是在这个类的底层,会在这个方法中开一个工作线程,而这个工作线程是从类的线程池中取的。我们可以将需要执行的耗时操作交给这个方法去执行(例如我们在上面提到的下载任务)。
onPreExecute()方法是执行在doInBackground方法之前的方法,它工作在主线程,主要用来初始化一些UI控件,为接下来的工作线程任务做准备,当然这个方法不是必须要重写,视情况而定。
onPostExecute(Result result)方法是执行在doInBackground方法之后的方法,它也是工作在主线程。当doInBackground方法执行完之后,会返回一个Result类型的对象,而onPostExecute(Result result)方法会根据这个result来实现对UI的更新。
publishProgress(Progress... values)方法和onProgressUpdate(Progress... values)方法,我们发现,这两个方法的参数是同一个类型的,再结合它们的方法名,我们不难想到,这两个方法是有一定的联系的。事实上,我们可能会需要在doInBackground方法执行的过程中就需要对UI进行更新,这个时候,onPostExecute方法就无法满足我们的需求了,这时,我们会用到这两个方法。publishProgress方法执行在工作线程,这个方法执行之后,主线程的onProgressUpdate方法很快会执行,它接收publishProgress方法传过来的参数,从而实现对UI的更新。
最后,别忘了最容易被忽略的execute方法,如果这个方法没有被执行,即使上面的几个方法写得再完美,这个异步任务根本就没有运行,又怎么会有结果呢!
通过上面的介绍,我们发现,AsyncTask中,有的方法(doInBackgroud方法)执行在工作线程,有的方法(其他方法)执行在主线程。首先,我们在onPreExecute方法中做一些准备工作,之后在doInBackgroud方法中执行耗时操作,在doInBackgroud方法执行过程中,我们如果需要对UI更新,那么可以使用publishProgress方法和onProgressUpdate方法对UI进行实时更新。当doInBackgroud方法执行完之后,我们在onPostExecute方法对UI进行最后的更新。这就是异步任务的简单流程。
下面我们通过一个模拟下载的耗时操作来简单运用一下异步任务。
public class MainActivity extends Activity {
//定义一个进度条和一个按钮
private ProgressBar pBar;
private Button btn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//对进度条和按钮进行初始化
pBar=(ProgressBar) findViewById(R.id.progressBar1);
btn=(Button) findViewById(R.id.button1);
//给btn加一个点击监听,点击后开始模拟下载
btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
new AsyncTask<Void, Integer, Void>() {
@Override
protected void onPreExecute() {
//下载之前给pBar设置一个最大值(在主线程)
pBar.setMax(10);
}
@Override
protected Void doInBackground(Void... params) {
//开始模拟下载,每一秒钟完成1/10(在工作线程)
for(int i=1;i<=10;i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {}
//发布下载进度,可以让主线程实时更新
publishProgress(i);
}
return null;
}
@Override
protected void onPostExecute(Void result) {
//10秒之后下载完成,将btn的文字改成“下载完成”(在主线程)
btn.setText("下载完成");
}
@Override
protected void onProgressUpdate(Integer... values) {
//通过publishProgress(i)传过来的参数,对pBar进行实时的更新(在主线程)
pBar.setProgress(values[0]);
}
}.execute();//很重要的execute,千万不能忘,忘了就功亏一篑了,切记切记切记!!!重要的说三遍
}
});
}
}
好了,这篇博客就写到这里了。