使用AsyncTask进行异步任务处理

使用AsyncTask进行异步任务处理

在程序开启后,就会有一个主线程,负责与用户交互。如果在主线程中执行了耗时操作,那么界面就会卡顿,直到耗时操作结束后才会继续响应,非常影响用户体验,所以要使用异步操作来完成这些耗时操作。本节我们介绍android提供的轻量级异步类——AsyncTask来做异步线程处理。

AsynTask有着轻量级、操作方便等特点,适用于简单的异步处理过程,可以很容易实现异步操作,并且提供接口反馈当前的异步执行状态给主线程。
我们通过一个实例来体会如何使用AsyncTask。假设我们需要实现一个功能:输入某个网址,点击按钮抓取网页源码并显示在屏幕上。

首先我们新建一个项目,在主程序布局文件activity_main.xml中使用线性布局(Linearlayout),拖入需要用到的EditText(输入网址用)、Button(点击用)和TextView(显示抓取结果)三个控件。再使用ScrollView包裹可能会超出屏幕的TextView。具体布局如下:

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
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="cn.edu.chd.asynctask.MainActivity">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/inputURL" />a
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="读取数据"
android:id="@+id/button"/>
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:id="@+id/textView" />
</ScrollView>
</LinearLayout>

然后使用findViewById()获取各个控件,并给Button建立监听,当此Button被点击后触发readURL()方法。代码片段如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private TextView text,urlText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text = (TextView) findViewById(R.id.textView);
urlText = (TextView)findViewById(R.id.inputURL);
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
url = urlText.getText().toString();
readUrl(url);
}
});
}

接着我们在readURL()中使用AsyncTask进行异步抓取目标网页数据。

AsyncTask定义了三种泛型类型Params、Progress、Result。Params指定了启动任务的执行参数(在本例中为URL的String类型),Progress指定了此异步任务执行进度,Result指定了后台执行任务最终返回的结果(本例中为返回的String类型网页内容)。

AsyncTask是抽象类,实例化必须要实现其抽象方法doInBackground ( String ... params )。我们一般通过实现以下几个方法来完成一个异步任务的执行:

  • doInBackground(String... params):该方法运行在子线程中,负责负责执行耗时操作,在onPreExecute()完成后立即执行;
  • onPreExecute():当前任务开始前的预处理,可以用来做一些UI准备工作,如显示进度对话框;
  • onPostExecute(String s):当后台操作结束时,此方法将会被调用,doInBackground()的结果将做为参数传递到此方法中,该方法可以用来显示处理结果;
  • onProgressUpdate(Void... values):在调用publishProgress(Progress... values)时,此方法被执行,直接将进度信息更新到UI组件上,该方法可以用来进度条的显示。
    我们来看完整的readURL方法:
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
public void readUrl(String url){
new AsyncTask<String ,Void,String>(){
//doInBackground方法内部执行后台任务,不可在此方法内修改UI
@Override
protected String doInBackground(String... params) {
try {
URL url = new URL(params[0]);
URLConnection urlConn = url.openConnection();
InputStream ins = urlConn.getInputStream();
InputStreamReader insr = new InputStreamReader(ins);
BufferedReader br = new BufferedReader(insr);
String line;
StringBuilder builder = new StringBuilder();
while ((line = br.readLine()) != null){
builder.append(line);
}
br.close();
insr.close();
return builder.toString();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
///onPreExecute方法用于在执行后台任务前做一些UI操作
@Override
protected void onPreExecute() {
text.setText(preText);
super.onPreExecute();
}
//onPostExecute方法用于在执行完后台任务后更新UI,显示结果
@Override
protected void onPostExecute(String s) {
text.setText(s);
super.onPostExecute(s);
}
}.execute(url);
}

我们来看一下运行结果:
AsyncTask运行截图
输入网址,点击读取数据,按钮立刻有了响应,抓取网页内容的任务在后台通过AsyncTask运行完毕,然后将结果返回给了UI主线程。

注意一定不要忘记对应用程序申请网络访问权限,即在AndroidManifest.xml中添加:<uses-permission android:name="android.permission.INTERNET"/>。否则是无论如何也抓取不到网址的结果的。

0%