在使用AsyncTask时,通常代码为:
AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
...
}
@Override
protected void onPostExecute(Void void) {
...
}
};
task.execute();
这样,在task调用execute方法后,就会创建一条线程用来运行定义在doInBackground方法中的代码,并在doInBackground方法运行完成后调用onPostExecute方法对ui进行更新。
如果我们定义一个这样的task:
AsyncTask<Void, Integer, Void> task1 = new AsyncTask<Void, Integer, Void>() {
@Override
protected Void doInBackground(Void... params) {
Integer progress = 0;
while (progress != 100) {
try {
progress++;
Thread.sleep(200);
publishProgress(progress, 1, 2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
}
@Override
protected void onProgressUpdate(Integer... values) {
int progress = values[0];
mProgressBar.setProgress(progress);
Log.e(TAG, "progress" + progress);
}
};
这个task的运行代码是每隔0.2s更新一次进度条的值。我们在启动应用后,就能看到进度条的值不断增加。在这段代码没有运行结束前,我们退出应用后可以发现线程仍在后台运行,这时如果再次打开应用,我们发现进度条的值为0,并暂时不会增加。一段时间后,进度条的值再次从0开始增加。
为了了解原因,再次定义一个task:
AsyncTask<Void, Void, Void> task2 = new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
for (int i = 0; i < 2000; i++) {
System.out.println("current index: " + i);
}
return null;
}
@Override
protected void onPostExecute(Void v) {
}
};
在运行顺序上,我们先调用task1的execute方法,再调用task2的execute方法。启动应用后,我们在可以发现在task1的代码运行结束后,才出现task2的运行代码。
基于以上两点:1.关闭应用后需等待一段时间后进度条的值才发生变化,我们可以理解为这时task才正式运行,也就是说先前的等待时间是因为上一个task正在运行。2.task2的运行代码在task1的运行代码全部运行结束后才开始运行,也就是说即使同时调用execute方法,task的运行仍有先后顺序。
可以猜测在AsyncTask中,应该存在一个队列,在task调用execute方法后,并不是立即创建对应的线程运行代码,而是将其加入到一个队列中,在先前的一个task运行结束后,再从队列中取出首部的task并创建线程进行运行。也就是说,即使一次性运行多个task,真正在线程中运行的task只有一个,采用先入先运行的方式处理所有的task。
注:如果是删除近期任务的方式关闭应用,那么task的线程就会被关闭。