为了解决新线程不能更新UI组件的问题,Android提供了以下解决方案:
①使用Handler实现线程之间的通信
②Activity.runOnUIThread(Runnable)
③View.post(Runnable)
④View.postDelayed(Runnable,long)
后面三种方式可能导致编程略显烦琐,而异步任务(AsyncTask)则可进一步简化操作
AsyncTask<>是一个抽象类,通常用于被继承,继承AsyncTask时需要指定三个泛型参数
AsyncTask<Params,Progress,Result>是抽象类,它定义了如下三种泛型
①Params:启动任务执行的输入参数类型,doInBackground(...)参数类型,也是调用execute(..)的参数类型。
②Progress:后台任务完成的进度值的类型,onProgressUpdate(...)参数类型
③Result:后台执行任务完成后返回结果的类型。doInBackground返回值类型,也是onPostExecute()参数类型。
使用AsyncTask的步骤:
①创建AsnycTask的子类,并未三个泛型参数指定类型,如果某个泛型参数不需要指定类型,可将它指定为void。
②根据需要实现AsnycTask的方法
1、doInBackground(Params...)重写该方法就是后台线程将要完成的任务,该方法可以调用publicProgress(Progress...values)方法更新任务的进度,每次调用该任务会触发onProgressUpdate(Progress...value)。
2、onProgressUpdate(Progress...values)在doInBackground()方法中调用publicProgress()方法更新任务的执行进度,将会触发该方法,所以该方法一般用于进度条之类的,用来提示用户任务的完成进度。
3、onPreExecute():该方法将在执行doInBackground()方法之前被调用,通常该方法用于UI控件的准备。
4、onPostExecute(Result result):当doInbackground()完成后,系统会自动调用onPostExecute()方法,并将doInBackground()方法的返回值传给该方法。
③调用AsnycTask子类实例的execute(Params...params)开始执行耗时任务
必须在UI线程中创建AsnycTask实例。
必须在UI线程中嗲用AsnycTask的execute()方法
每个AsyncTask只能被执行一次,多次调用将会引发异常。
简单实用AsyncTask实例:
<span style="font-family:Courier New;font-size:14px;">//生成该类的对象,并调用其execute方法之后
//首先执行的的onPreExecute方法
//其次是执行doInBackground方法
public class ProgressBarAsyncTask extends AsyncTask<Integer, Integer, String> {
private TextView textView = null;
private ProgressBar progressBar = null;
public ProgressBarAsyncTask(TextView textView, ProgressBar progressBar) {
this.textView = textView;
this.progressBar = progressBar;
}
// 该方法并不运行在UI线程当中,所以在该方法当中,不能对UI当中的控件进行设置和修改
// 主要用于进行异步操作。
@Override
protected String doInBackground(Integer... params) {
NetOperator netOperator = new NetOperator();
int i = 0;
for (i = 10; i <= 100; i += 10) {
netOperator.operate();
// 用于发布更新消息
publishProgress(i);
}
return i + params[0].intValue() + "";
}
// 在doInBackground方法当中,每次调用publishProgress()方法之后,都会触发该方法
// 用于在异步任务执行的过程当中,对用户进行提示,例如控制进度条等
@Override
protected void onProgressUpdate(Integer... values) {
int value = values[0];
progressBar.setProgress(value);
}
// 该方法表示doInBackfround执行完成后,系统会自动调用该方法,并将doInBackground方法的返回值传给该方法
// 在doInBackground方法执行结束之后再运行,并且运行在UI线程当中。
// 主要用于将异步任务执行的结果展示给客户
@Override
protected void onPostExecute(String result) {
textView.setText("异步操作执行结束" + result);
}
// 异步任务开始时最先执行的就是这个方法,是UI线程,该方法主要用于UI的设置
//该方法运行在UI线程当中,主要用于进行异步操作之前的UI准备工作
@Override
protected void onPreExecute() {
textView.setText("异步任务开始");
}
}</span>
MainActivity中调用
<span style="font-family:Courier New;font-size:14px;">public class MainActivity extends Activity {
private Button button = null;
private ProgressBar progressBar = null;
private TextView textView = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button)findViewById(R.id.button);
progressBar = (ProgressBar)findViewById(R.id.progressBar);
textView = (TextView)findViewById(R.id.textView);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
ProgressBarAsyncTask asyncTask = new ProgressBarAsyncTask(textView, progressBar);
asyncTask.execute(1000);
}
});
}
}</span>
NetOperator
<span style="font-family:Courier New;font-size:14px;">//模拟访问网络的操作
public class NetOperator {
public void operate(){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}</span>