一、知识点
1、为了解决新线程不能更新UI组建的问题,Andorid提供了如下几种解决方案:
- 使用Handler实现线程之间的通信
- Activity.runOnUiThread(Runnable)
- View.post(Runnable)
- View.postDelayed(Runnable)
2、在Android应用程序中,在Android中UI线程响应不能超过5s,否则会出现ANR,因此我们常常将耗时操作放在非工作线程中执行,为了避免ANR(Application Not Response)异常,需要把耗时任务放置在子线程中来完成,或者使用AsyncTask类来完成;AsyncTask主要用来更新UI线程,比较耗时的操作可以在AsyncTask中使用。
3、AsyncTask的特点 :更轻量级一些,适用于简单的异步处理,不需要借助线程和Handler即可。
4、AsyncTask<Params,Progress,Result>,是一个抽象类,通常用于被继承,继承后,需要制定如下三个泛型参数:
- Params: 启动任务执行的输入参数类型
- Progress:后台任务完成的进度值的类型
- Result:后台执行任务完成后返回结果的类型
(1).创建AsyncTask的子类,并为三个泛型参数指定类型。如果某个泛型参数不需要指定类型,可将它指定为void。
(2).根据需要,实现AsyncTask的如下方法:
- onPreExecute():准备运行后台任务时。一般做一些初始化工作(如:显示进度对话框)。 注意,这个方法在UI线程(主线程)中执行
- doInBackground(Params …):正在后台运行。在后台线程中执行。一般编写需要在后台线程中执行的代码。注意,这个在后台线程中执行。
- onProgressUpdate(Progress... values):进度更新时。一般就是更新进度显示。注意,这个方法在UI线程(主线程)中执行。一般在doInBackground()方法中调用publishProgress()方法来触发。
- onPostExecute(Result result):当doInBackground()完成后,系统会自动调用onPostExecute()方法,并将doInBackground方法返回的值传给该方法。一般做一些清理资源工作(如:隐藏进度对话框)。 注意,这个方法在UI线程(主线程)中执行
(3).调用AsyncTask子类的实例的execute(Params... params)开始执行耗时任务。
6、AsyncTask异步加载时序图
7、使用AsyncTask时必须遵守的规则
- 必须在UI线程中创建AsyncTask的实例。
- 必须在UI线程中调用AsyncTask的execute()方法。
- AsyncTask的onPreExecute()、onPostExecute(Result result)、doInBackground(Params... params)、onProgressUpdate(Progress... values)方法,不应该由程序员代码调用,而是由Android系统负责调用。
- 每个AsyncTask只能被执行一次,多次调用将会引发异常。
二、实战
例1:
1、效果图
2、demo目录
3、xml文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="@+id/show"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textSize="21dp" />
</LinearLayout>
<Button
android:id="@+id/update"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="updateClick"
android:text="更新"
android:textSize="21dp" />
</LinearLayout>
4、代码
package com.BieWong.asynctaskupadate;
import android.app.Activity;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity {
Button update;
TextView show;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
initView();// 初始化相应的UI组件
setOnClickListener();// 对按钮进行监听
}
private void setOnClickListener() {
update.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
AsynctaskUpdate ast = new AsynctaskUpdate(MainActivity.this);
ast.execute();
}
});
}
private void initView() {
update = (Button) findViewById(R.id.update);
show = (TextView) findViewById(R.id.show);
}
// 创建内部类继承AsyncTask的方法
class AsynctaskUpdate extends AsyncTask<Void, Integer, Integer> {
// 定义Context用于传递上下文
Context mContext;
// 定义相应的构造器接受外部类的Context
public AsynctaskUpdate(Context context) {
mContext = context;
}
// 准备运行后台任务时。一般做一些初始化工作
@Override
protected void onPreExecute() {
Toast.makeText(mContext, "执行任务开始", 2000).show();
}
// 后台运行的方法,可以运行非UI线程,可以执行耗时的方法
@Override
protected Integer doInBackground(Void... params) {
int i = 0;
while (i < 100) {
i++;
// 调用publisProgress(),把参数传递给onProgressUpdate(Integer... values)
publishProgress(i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
}
// 接收在publishProgress()被调用以后执行的数据,用于更新进度
@Override
protected void onProgressUpdate(Integer... values) {
show.setText(values[0].toString());
}
// 运行在ui线程中,在doInBackground()执行完毕后执行
@Override
protected void onPostExecute(Integer result) {
Toast.makeText(mContext, "执行任务完成", 2000).show();
}
}
}
例2:1、效果图
2、demo目录
3、xml文件
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="@+id/show"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="20dp" />
</ScrollView>
<Button
android:id="@+id/download"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:text="下载"
android:textSize="21dp" />
</RelativeLayout>
4、代码文件
package com.example.asynctaskdownload;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ScrollView;
import android.widget.TextView;
public class MainActivity extends ActionBarActivity {
TextView show;
Button download;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
show = (TextView) findViewById(R.id.show);
download = (Button) findViewById(R.id.download);
download.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
DownTask task = new DownTask(MainActivity.this);
try {
task.execute(new URL("http://www.xiaomi.cn"));
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
class DownTask extends AsyncTask<URL, Integer, String> {
ProgressDialog pdialog;
// 定义记录已经读取行的数量
int hasRead = 0;
Context mContext;
public DownTask(Context ctx) {
mContext = ctx;
}
@Override
protected void onPreExecute() {
pdialog = new ProgressDialog(mContext);
// 设置对话框的标题
pdialog.setTitle("任务正在执行中");
// 设置对话框显示的内容
pdialog.setMessage("任务正在执行中,敬请等待...");
// 设置对话框不能用“取消”按钮关闭
pdialog.setCancelable(false);
// 设置该进度条的最大进度值
pdialog.setMax(2000);
// 设置对话框的进度条风格
pdialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
// 设置对话框的进度条是否显示进度
pdialog.setIndeterminate(false);
pdialog.show();
}
@Override
protected String doInBackground(URL... params) {
StringBuilder sb = new StringBuilder();
try {
// 打开params数组的第一个的URL
URLConnection conn = params[0].openConnection();
// 打开conn连接对应的输入流,并将它包装成BufferedReader
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
String line = null;
while ((line = br.readLine()) != null) {
// sb连接每次读完一行的数据,并换行
sb.append(line + "\n");
hasRead++;
// publishProgress()把数据传递给onProgressUpdate()
publishProgress(hasRead);
}
// 返回sb的值给onPostExecute() 方法,不能少!!
return sb.toString();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onProgressUpdate(Integer... values) {
// 更新进度
show.setText("已经读取了" + values[0] + "行数据!");
// 设置对话框进度条的进度值
pdialog.setProgress(values[0]);
}
@Override
protected void onPostExecute(String result) {
// 接收 doInBackground()方法的返回值,也就是HTML页面的内容
show.setText(result);
// 关闭对话框
pdialog.dismiss();
}
}
}
5、AndroidManifest.xml文件内需要声明如下权限,来访问网络 <uses-permission android:name="android.permission.INTERNET" />