于UI线程中比较耗时的工作,开启一个子线程来处理这些工作: 首先创建一个Thread对象,然后调用start( )方法启动新的子线程。
使用子线程解决异步执行带来的新问题: 在Android中,只有UI线程(即主线程)才可以更新主UI界面,而其子线程不能更新UI视图。
使用多线程实现:AsyncTask
AsyncTask能够适当地、简单地用于UI线程,这个类准许执行后台操作。
异步任务的定义是一个在后台线程上运行,其结果是在UI线程上显示的一种类。
AsyncTask的四个方法
- onPreExecute():任务被执行之前调用UI线程。
- 这步通常被用于设置任务,例如在用户界面显示一个进度条。
- doInBackground(Params...):onPreExecute()执行完成,立刻调用后台线程。
- 这步被用于执行较长时间的后台任务;
- 异步任务的参数也被传到这步;
- 计算的结果在这步返回,将传回到上一步。
- onProgressUpdate(Progress...):一次呼叫
publishProgress(Progress...)后调用UI线程,执行的时机没有定义。
- 这个方法用于在用户界面显示进度,当后台计算还在进行时。
- 例如:这个方法可以被用于一个进度条动画或在文本域显示日志。
- onPostExecute(Result):当后台计算结束时,调用UI线程。
- 后台计算结果作为一个参数传递到此方法中。
异步任务的创建:
- AsyncTask必须被子类继承。
子类至少重写其中的doInBackground(Params...)方法,一般还会重写onPostExecute(Result)。
- 任务实例必须创建在UI线程。
- execute(Prams…)必须在UI线程上调用。
- 不要手动调用onPreExecute(), onPostExecute(), doInBackground(), onProgressUpdate()。
- 不能在doInBackground(Params... params)中更改UI界面。
异步任务中的三个泛型:
- Params:任务执行器需要的数据类型。
- Progress:后台计算中使用的进度单位数据类型。
- Result:后台计算返回结果的数据类型。
示例(模拟下载进度条):
import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
private Button btnStart = null;
private ProgressBar prbRate = null;
private TextView tvResult = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnStart = findViewById(R.id.btn_start);
prbRate = findViewById(R.id.prb_rate);
tvResult = findViewById(R.id.tv_result);
btnStart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
DownLoadTask downLoadTask = new DownLoadTask(prbRate,tvResult);
downLoadTask.execute();
}
});
}
/*
*/
public class DownLoadTask extends AsyncTask<Integer,Integer,Integer> {
private ProgressBar prbRate = null;
private TextView tvResult = null;
public DownLoadTask(ProgressBar prbRate,TextView tvResult){
this.prbRate = prbRate;
this.tvResult = tvResult;
}
@Override
protected Integer doInBackground(Integer... integers) {
//模拟下载过程
int i= 0;
for(; i<=100;i++){
publishProgress(i);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return 100;
}
@Override
protected void onProgressUpdate(Integer... values) {
tvResult.setText("正在下载:"+values[0] + "%");
prbRate.setProgress(values[0]);
}
@Override
protected void onPreExecute() {
tvResult.setText("开始下载");
}
@Override
protected void onPostExecute(Integer integer) {
tvResult.setText("下载完成:" + integer + "%");
}
// @Override
// /*
// 在真正的异步任务之前,本方法被调用
// 完成异步任务的相关初始化
// 可以再之前更新界面
// 【1】
// */
// protected void onPreExecute() {
// super.onPreExecute();
// }
//
// @Override
// /*
// 【3】
// 可以在执行异步任务的过程中更新UI界面
// 由doInBackground方法决定,通过调用一个方法publishProgress
// 以回调的方式被调用
// */
// protected void onProgressUpdate(Object[] values) {
// super.onProgressUpdate(values);
// }
//
// @Override
// /*
// 在异步任务结束之后本方法被调用
// 完成异步任务的收尾工作
// */
// protected void onPostExecute(Object o) {
// super.onPostExecute(o);
// }
//
// @Override
// /*
// 唯一在子线程中执行,前面三个在UI主线程执行
// 【2】子线程,真正执行异步任务的方法,这个方法执行在子线程当中,
// 用于执行耗时操作或远程链接下载
// 不能更新UI界面
// */
// protected Object doInBackground(Object[] objects) {
// return null;
// }
}
}