Android的线程状态——AsyncTask
前言:在上一章节,我们学习了什么是Handler,以及涉及到的关键词UI线程和子线程。这一章节,我们将去学习什么AsyncTsak,也会知道AsyncTsak与Handler有异曲同工之妙。
(一)什么是AsyncTask
概念:
我们知道Handler是一种Android中一种处理异步消息的核心类,而 AsyncTask其实也可以这么定义。但是我们知道使用Handler时,我们需要自己去创建子线程,但是AsyncTask则不需要。这并不代表它就用不到子线程,而是AsyncTask在执行耗时操作时,系统会帮助启动子线程。所以AsyncTask被称为轻量级(实现代码量少)的异步类。
(二)AsyncTask的优点:
- 代码量少;
- 减低开发者的开发难度;
- 直接继承于Objict类;
- 可以忽略Looper、MessagQueue、Handler等复杂对象,实现更便捷地完成异步耗时操作。
(三)如何使用AsyncTask
步骤:
通过上面这张图,我们可以看到它告诉我们需要重写几个方法,但是也省略掉一些步骤,下面我就总结一下AsyncTask的使用步骤。
- 新建内部类继承AsyncTask;
- 定义AsyncTask的三种泛型参数(所谓泛型参数,其实就是任何类型的参数啦);
- 重写doInBackground()抽象方法,而我们需要做的耗时操作就是在这里面执行的。记住,此方法在AsyncTask中是必有的;(运行在子线程中)
- 重写onRreExecute()方法和onPostExecute()方法,这里可以根据需要来决定是否用它们;(皆运行在UI线程中)
- 当需要AsyncTask带进度时,则需要用到onProgressUpdate()方法。在此之前,我们需要用到publishProgress方法来触发onProgerssUpdate()方法,而publishProgerss方法则是在doInBackground()方法中使用,也可以参考上面图片进行理解;
- 最后在需要启动的地方调用execute方法或executeOnexecutor方法,后面我们会讲到这两者之间的差别。
(四)AsyncTask使用案例
1)不带进度
题目:点击Button按钮进行下载,TextView中的内容由“开始下载”变为正在下载,下载时间为5秒,下载完成后变为“完成下载”。
效果展示:
代码演示:
- 为Button添加监听;
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- 新建内部类继承AsyncTask;
class MyProgress extends AsyncTask<String,Integer,String>{
- 重写doInBackground方法,执行耗时操作;
@Override
protected String doInBackground(String... strings) {
for (int i=0;i<5;i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return "完成下载";
}
- 获得return传到onPostExecute方法中的返回值;
- 在需要启动的地方调用execute方法。
new MyProgress().execute();
2)带进度
题目:在EditText中输入一个数,点击Button按钮进行倒计时。
效果展示:
代码演示:
jishiBTN.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int time=Integer.parseInt(jishiET.getText().toString());
new JishiProgress().execute(time);
}
});
class JishiProgress extends AsyncTask<Integer,Integer,String>{
@Override
protected String doInBackground(Integer... integers) {
for(int i=integers[0];i>0;i--){
try {
Thread.sleep(1000);
publishProgress(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return "计时结束";
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
jishiTV.setText("倒计时:"+values[0]);
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
jishiTV.setText(s);
}
}
题目:点击按钮,按钮修改为正在下载且在下载时不能点击按钮,使用进度条显示进度,下载完成后按钮修改为下载完成。
效果展示:
代码演示:
1.XML行布局创建progressBar和Button控件,并设置progressBar为水平进度条;
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
2.Acitivity
public class JinduActivity extends AppCompatActivity implements View.OnClickListener{
private ProgressBar jinduPB;
private Button jinduBTN1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_jindu);
bindID();
}
private void bindID() {
jinduPB=findViewById(R.id.jindu_pb);
jinduBTN1=findViewById(R.id.jindu_btn);
jinduPB.setMax(10);
jinduBTN1.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.jindu_btn:
jinduBTN1.setEnabled(false);
new JinduProgress().execute();
break;
}
}
class JinduProgress extends AsyncTask<Integer,Integer,Integer>{
@Override
protected Integer doInBackground(Integer... integers) {
for(int i=0;i<=10;i++){
try {
Thread.sleep(1000);
publishProgress(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return 1;
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
jinduPB.setProgress(values[0]);
}
@Override
protected void onPostExecute(Integer integer) {
super.onPostExecute(integer);
jinduBTN1.setText("下载完成");
jinduBTN1.setEnabled(true);
}
}
}
题目:在上一题的基础上,实现两个进度条的并行加载。
效果展示:
代码演示:
public class TwoJDActivity extends AppCompatActivity implements View.OnClickListener {
private ProgressBar bar1;
private ProgressBar bar2;
private Button btn1;
private Button btn2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_two_jd);
bindID();
}
private void bindID() {
bar1 = findViewById(R.id.two_bar1);
bar2 = findViewById(R.id.two_bar2);
btn1 = findViewById(R.id.two_btn1);
btn2 = findViewById(R.id.two_btn2);
bar1.setMax(10);
bar2.setMax(10);
btn1.setOnClickListener(this);
btn2.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.two_btn1:
btn1.setText("正在下载");
btn1.setEnabled(false);
new TwoProess().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,1);
break;
case R.id.two_btn2:
btn2.setText("正在下载");
btn2.setEnabled(false);
new TwoProess().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,2);
break;
}
}
class TwoProess extends AsyncTask<Integer,Integer,Integer>{
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected Integer doInBackground(Integer... integers) {
int WhichPb=integers[0];
for(int i=1;i<=10;i++){
try {
Thread.sleep(1000);
publishProgress(i,WhichPb);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return WhichPb;
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
switch (values[1]){
case 1:
bar1.setProgress(values[0]);
break;
case 2:
bar2.setProgress(values[0]);
break;
}
}
@Override
protected void onPostExecute(Integer integer) {
super.onPostExecute(integer);
switch (integer){
case 1:
btn1.setText("下载完成");
btn1.setEnabled(true);
break;
case 2:
btn2.setText("下载完成");
btn2.setEnabled(true);
break;
}
}
}
}
(五)execute和excuteOnExcutor的区别
其实这两者之间的区别很容易记住,excute使进度条串行,即一个进度条下载完成之后,第二条进度条才开始下载。而excuteOncutor则可以使几个进度条同时运行。
(六)倾向于Handler还是AsyncTask?
我个人更喜欢用AsyncTask,原因很简单,代码少,更快捷。