正所谓说不如做,今天我们通过一个Demo快速上手AsyncTask。
为了解决新线程不能更新UI组件的问题,Android提供了许多解决方案,这里我们使用更轻量级的AsyncTask,适用于简单的异步处理,不需借助线程和Handler即可实现。
AsyncTask是一个抽象类,继承时需指定如下三个泛型参数:
- Params 启动任务执行的输入参数的类型,比如HTTP请求的URL。
- Progress 后台任务执行的百分比类型,比如Integer。
- Result 后台执行任务最终返回的结果,比如String。
public abstract class AsyncTask<Params, Progress, Result> {
使用AsyncTask通过如下三步:
1.继承AsyncTask并为三个泛型参数指定类型,不需要则指定为void。
2.根据需要实现他的方法:
- doInBackground(Params…) 后台执行,比较耗时的操作都可以放在这里。注意这里不能直接操作UI。此方法在后台线程执行,完成任务的主要工作,通常需要较长的时间。可以调用publishProgress(Progress…)来更新任务的进度。
- onProgressUpdate(Progress…)可以使用进度条增加用户体验度。 此方法在主线程执行,用于显示任务执行的进度。doInBackground调用publishProgress时触发此方法。
- onPreExecute()当任务执行之前开始调用此方法,完成一些初始化准备工作,可以在这里显示进度对话框。
- onPostExecute(Result) 相当于Handler 处理UI的方式,在这里面可以使用在doInBackground 得到的结果处理操作UI。 此方法在主线程执行,任务执行的结果作为此方法的参数返回。
3.调用AsyncTask子类的实例execute执行任务。
使用AsyncTask类,以下是几条必须遵守的准则:
- Task的实例必须在UI thread中创建;
- execute方法必须在UI thread中调用;
- 不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法,应该由Android系统调用。
- 该task只能被执行一次,否则多次调用时将会出现异常;
下面看一个下载的小Demo,快速上手。
我们先写布局文件,一个线性布局LinearLayout里面有一个Button触发下载操作,一个ScrollView里面包着一个TextView用于显示内容。
<?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:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="startTask"
android:text="AsyncTask" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/show_tv_main"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Hello World!" />
</ScrollView>
</LinearLayout>
然后我们开始核心代码的编写:
1.继承AsyncTask并为三个泛型参数指定类型,不需要则指定为void:
class DownTask extends AsyncTask<URL,Integer,String>{
2.根据需要实现他的方法:
在onPreExecute中进行预处理操作,设置ProgressDialog:
@Override
protected void onPreExecute() {
progressDialog = new ProgressDialog(mContext);
progressDialog.setTitle("任务正在执行中···");
progressDialog.setMessage("惟楚有才,权兴权意.");
progressDialog.setCancelable(false);
progressDialog.setMax(200);
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDialog.show();
}
在doInBackground中进行耗时网络访问操作:
@Override
protected String doInBackground(URL... urls) {
StringBuilder stringBuilder = new StringBuilder();
try {
URLConnection urlConnection = urls[0].openConnection();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(),"utf-8"));
String line = null;
while((line = bufferedReader.readLine()) != null){
stringBuilder.append(line + "\n");
hasRead++;
publishProgress(hasRead);
}
return stringBuilder.toString();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
doInBackground调用publishProgress时触发此方法,在onProgressUpdate中进行进度更新:
@Override
protected void onProgressUpdate(Integer... values) {
showContent.setText("已读:" + values[0] + "行.");
progressDialog.setProgress(values[0]);
}
在onPostExecute中进行收尾操作,设置内容,隐藏ProgressDialog:
@Override
protected void onPostExecute(String result) {
showContent.setText(result);
progressDialog.dismiss();
}
3.在Button的响应方法中调用AsyncTask子类的实例execute执行任务:
public void startTask(View view) throws MalformedURLException{
DownTask downTask = new DownTask(this);
downTask.execute(new URL("https://www.uc123.com/"));
}
最后,因为我们涉及到了对网络的访问,别忘了添加相应权限:
<uses-permission android:name="android.permission.INTERNET"/>
效果如图:
完整源代码如下:
package com.quan.car.asynctask;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
/**
* 权兴权意-2016.11.23
* 一个Demo快速上手AsyncTask
*/
public class MainActivity extends Activity {
private TextView showContent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
showContent = (TextView) findViewById(R.id.show_tv_main);
}
public void startTask(View view) throws MalformedURLException{
DownTask downTask = new DownTask(this);
downTask.execute(new URL("https://www.uc123.com/"));
}
class DownTask extends AsyncTask<URL,Integer,String>{
ProgressDialog progressDialog;
int hasRead = 0;
Context mContext;
public DownTask(Context context){
mContext = context;
}
@Override
protected String doInBackground(URL... urls) {
StringBuilder stringBuilder = new StringBuilder();
try {
URLConnection urlConnection = urls[0].openConnection();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(),"utf-8"));
String line = null;
while((line = bufferedReader.readLine()) != null){
stringBuilder.append(line + "\n");
hasRead++;
publishProgress(hasRead);
}
return stringBuilder.toString();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onProgressUpdate(Integer... values) {
showContent.setText("已读:" + values[0] + "行.");
progressDialog.setProgress(values[0]);
}
@Override
protected void onPostExecute(String result) {
showContent.setText(result);
progressDialog.dismiss();
}
@Override
protected void onPreExecute() {
progressDialog = new ProgressDialog(mContext);
progressDialog.setTitle("任务正在执行中···");
progressDialog.setMessage("惟楚有才,权兴权意.");
progressDialog.setCancelable(false);
progressDialog.setMax(200);
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDialog.show();
}
}
}