Contents
  1. 1. 如何调用
  2. 2. onPreExecute 方法
  3. 3. doInBackground 方法
  4. 4. onProgressUpdate 和 onPostExecute

实际开发过程中,我们难免会遇到需要异步操作的场景:

例如用户下载升级文件,要让用户能够看到下载进度,同时完成后能点击安装,那下载的过程就是在另一个线程中完成,同时进度的显示则是要实时通知到UI主线程中的。
类似这样的轻量级的异步操作还有很多,那Android就给我们提供了一个方便的类AsyncTask来实现。

照旧先上代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
private class DownloadFileTask extends AsyncTask<String,Double,Double> {
/**
* Description: 异步动作执行之前,一般用来处理UI,例如显示提示框等
*/
@Override
protected void onPreExecute() {
LogUtils.i(TAG, "onPreExecute");
super.onPreExecute();
}

/**
* Description: 后台执行的动作
* 如果有需要UI实时响应的,通过publishProgress方法传递给onProgressUpdate()
* return的值会被onPostExecute()方法接收到并做进一步的处理
*/
@Override
protected Double doInBackground(String... params) {
LogUtils.i(TAG, "doInBackground param:" + params[0] + "," + params[1] + "," + params[2]
+ "," + params[3]);
// 设置进度值
publishProgress(你自己的获取到的进度值);
// 最后返回值
double time_interval = CommonUtils.downloadFileFromURL(params[1],params[2],params[3]);
return time_interval;
}

/**
* Description: 用于更新进度信息
* 一般在doInBackground方法中调用本方法来公布进度,最后onProgressUpdate方法将被执行
*/
@Override
protected void onProgressUpdate(Double... progresses) {
Log.i(TAG, "onProgressUpdate(Progress... progresses) called");
super.onProgressUpdate();
}


/**
* Description: 异步执行完成之后更新UI主进程
* Created by KAKA on 16/2/16 17:01
*/
@Override
protected void onPostExecute(Double result) {
Log.d(TAG, "onPostExecute result=" + result);
}

以上的代码是一个最基本、最简单的没有经过太多处理的AsyncTask类,我们来分别详细看一下关于这个类的说明。

如何调用

  1. 我们可以看到在AsyncTask类后是有三种泛型类型,分别代表“启动任务执行的输入参数”“后台任务执行的进度”“后台计算结果的类型”。在特定场合下,并不是所有类型都被使用,如果没有被使用,可以用java.lang.Void类型代替;

  2. 通过调用new DownloadConfigureFile.execute(Params... params),执行一个异步任务,需要我们在代码中调用此方法,触发异步任务的执行,其中可以输入多个参数。

  3. 参数个数和类型看我们每个人的程序实际需要来完成了。比如我的程序中,CommonUtils.downloadFileFromURL(params[1],params[2],params[3])方法需要3个参数,那么我要在UI主线程中启动AsyncTask异步线程,就要这样写:
    new DownloadFileTask().execute("2",download_url,"FILE","PATH");
    那么最终download_url,FILE和PATH就回被作为函数的形参正确地传了进去。

onPreExecute 方法

正如我在注释中写到的内容一样:本方法主要用于异步动作执行之前,一般用来处理UI,例如显示提示框等。
在我的样例代码中并没有写任何内容,因为本身我的处理逻辑就是后台下载文件的任务,不需要用户做出什么响应,也不需要用户感知到。但是我们可以在这个方法中随意做一些我们希望提示在UI界面上的内容,比如如果当前不是WiFi环境,要弹出提示框,询问用户是否要继续下载等等。

doInBackground 方法

注意这个方法是有返回值的,返回值的类型和AsyncTask泛型中的第3个参数类型保持一致。从本方法的字面上我们也能很清楚地了解到,这个方法就是用于在后台执行任务的,它可以随时在UI界面上做提醒,相应的动作可以通过调用publishProgress方法来实现,方法中传入的值会被onProgressUpdate接收到,同时在执行完之后,返回的值会被onPostExecute接收并处理。
这里附带上我的程序中后台下载任务CommonUtils.downloadFileFromURL()方法的原代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
/**
* Description: 从指定的URL中下载文件到程序的文件夹中
* Created by KAKA on 16/2/15 15:44
* @param url_address 文件所在地址
* @param filename 文件名称
* @param local_path 本地存入的文件夹名称,例如 splash, config等
* @return 从下载开始到下载完成的时间间隔,如果失败则返回-1
*/
public static double downloadFileFromURL(String url_address, String filename, String local_path)
{
// 本地应用的目录,文件夹名称是传递进来的形参local_path
File file_dir = context.getDir(local_path,Context.MODE_PRIVATE);
// 创建一个新的文件
File file = new File(file_dir,filename);
// 下载文件的url对象
URL url;
// 返回的记录时间的值
double time_interval;
try {
url = new URL(url_address);
long start_time = System.currentTimeMillis();

URLConnection url_conn = url.openConnection();
url_conn.setReadTimeout(5000);
url_conn.setConnectTimeout(5000);

InputStream input_stream = url_conn.getInputStream();
BufferedInputStream buffer_input_stream = new BufferedInputStream(input_stream);

// 申请1M的空间
ByteArrayBuffer byte_array_buff = new ByteArrayBuffer(1024*1024);
int current;
while((current = buffer_input_stream.read()) != -1) {
byte_array_buff.append((byte) current);
}

FileOutputStream file_output_stream = new FileOutputStream(file);
file_output_stream.write(byte_array_buff.toByteArray());
file_output_stream.flush();
file_output_stream.close();

time_interval = (System.currentTimeMillis() - start_time)/1000.0;
LogUtils.i("文件下载成功", "耗时" + (System.currentTimeMillis() - start_time) + "毫秒");
return time_interval;
} catch(IOException e) {
e.printStackTrace();
return -1;
}
}

onProgressUpdate 和 onPostExecute

这两个方法也能从字面上理解出来,一个是进度的更新,一个是完成之后的更新。这里就不再展开罗列了。
进度的更新我们可以做一个进度条,显示下载的进度;完成之后的动作比如说是否提示用户安装等等。

Contents
  1. 1. 如何调用
  2. 2. onPreExecute 方法
  3. 3. doInBackground 方法
  4. 4. onProgressUpdate 和 onPostExecute