正文
版权声明:本文为博主原创文章,未经博主允许不得转载
源码:
github.com/AnliaLee
大家要是看到有错误的地方或者有啥好的建议,欢迎留言评论
前言
本章我们将结合之前几篇博客,来研究研究多线程知识综合应用程度很高的
AsyncTask
类(Android 7.0版本)
往期回顾
大话Android多线程(一) Thread和Runnable的联系和区别
大话Android多线程(二) synchronized使用解析
大话Android多线程(三) 线程间的通信机制之Handler
大话Android多线程(四) Callable、Future和FutureTask
大话Android多线程(五) 线程池ThreadPoolExecutor详解
AsyncTask简介
通过之前几篇博客的学习和研究,我们知道了要将
耗时的任务
放到
子线程
中执行,然后使用
Handler
机制通知
UI线程
任务的结果并执行
更新UI
的操作。如果这些步骤都由我们自己动手去写,势必会让代码显得非常臃肿
Android给我们提供了一种轻量级的异步任务类
AsyncTask
,该类实现了异步操作,并提供相应的接口反馈
异步任务执行结果及进度
,实现了
从子线程执行任务到通知主线程更新UI
的一条龙服务,大大减少了我们的开发工作。下面我们将从如何使用开始逐步揭开
AsyncTask
的神秘面纱
如何使用AsyncTask
我们以去快餐店点餐为例。我们将顾客点餐与取餐的行为放在
主线程
中(
更新UI界面
等操作),而服务人员在厨房配餐的行为放在
子线程
中进行(在后台执行
耗时操作
)
顾客不会关心服务人员在厨房是如何工作的,他们只关心点了什么(配置参数并调用
AsyncTask.execute
进行提交)以及何时收到通知去取餐(在
AsyncTask.onPostExecute
回调方法中接收
后台任务返回的结果
,并执行相应的操作)。服务人员在配餐之前可以帮助顾客准备餐盘、纸巾等等,当然这些工作对顾客来说是可见的(通过重写
AsyncTask.onPreExecute
回调方法执行一些耗时任务之前的准备工作,该方法运行在
主线程
中)。准备工作完毕后,服务人员会通知厨房进行配餐,这部分工作对于顾客来说是不可见的(在
AsyncTask.doInBackground
方法中编写执行
耗时任务
的代码,这些
耗时任务
运行在
子线程
中)。配餐完毕后,通知顾客来取餐(
AsyncTask.doInBackground
结束时会返回一个值,该值会传递到
AsyncTask.onPostExecute
中,证明耗时任务已经执行完毕)
整个流程简单总结一下就是
开始任务
(
execute
) →
任务准备
(
onPreExecute
) →
执行任务
(
doInBackground
) →
反馈任务结果
→
回到主线程执行相应操作
(
onPostExecute
)
下面我们来看具体的代码(关于使用
AsyncTask
会导致
内存泄漏
的问题请看文末的补充,这里的代码只是简单实现就不多赘述了)
public class AsyncTaskTestActivity extends AppCompatActivity {
TextView textShow;
@Override
protected void onCreate (Bundle savedInstanceState) {
super .onCreate(savedInstanceState);
setContentView(R.layout.activity_async_task_test);
textShow = (TextView) findViewById(R.id.text_show);
}
public void clickEvent (View view) {
switch (view.getId()) {
case R.id.btn_start:
List<String> list = new ArrayList<>();
list.add("薯条" );
list.add("汉堡" );
list.add("可乐" );
new MyAsyncTask().execute(list);
break ;
}
}
public class MyAsyncTask extends AsyncTask <List <String >,String ,String > {
@Override
protected void onPreExecute () {
super .onPreExecute();
textShow.setText("餐盘准备好了,开始配餐..." );
}
@Override
protected void onPostExecute (String s) {
super .onPostExecute(s);
textShow.setText("配餐完毕," + s);
}
@Override
protected String doInBackground (List<String>... params) {
String foods = "已经配好的食物 —— " ;
try {
for (String str : params[0 ]){
Thread.sleep(1000 );
foods = foods + str + " " ;
Log.e("白胡子快餐店" ,foods);
}
}catch (Exception e){}
return foods;
}
}
}
运行效果如图所示
我们来分析一下上述代码中的细节
使用
AsyncTask
首先得实现它的子类,我们先来看下抽象类
AsyncTask
的部分源码
public abstract class AsyncTask <Params , Progress , Result >
这里告诉我们如果要继承
AsyncTask
,需配置3个
泛型参数
的具体类型,这3个参数的介绍如下
Params
:
开始执行异步任务
时需传入的参数类型,即
AsyncTask.execute
方法中要传递的参数类型。例如我们将
Params
设为
String
类型,那么将调用
execute(String s)
方法
开始任务
,提交的参数
s
类型为
String
。另外此参数类型同样和传入
AsyncTask.doInBackground
方法的参数相对应
ps
:如果不需要传递任何参数,则可以将参数类型设为
Void
,那么
开始任务
时只需要调用
execute()
即可,下同(返回参数同理)
Progress
:
执行异步任务过程中
向
主线程
传递的
进度值的类型
。我们可以在
AsyncTask.doInBackground
方法中调用
publishProgress
方法告知
主线程
当前耗时任务的执行进度,我们设置的
进度值类型
即
publishProgress
方法要传递参数的类型
Result
:
任务执行完毕
后,返回的
结果类型
,即
AsyncTask.doInBackground
方法
返回值
的类型,也是
AsyncTask.onPostExecute
方法
传入参数
的类型
结合之前的代码,在我们实现的
AsyncTask
子类中,
Params
设为
List<String>
类型,
Progress
设为
String
类型,
Result
设为
String
类型
public class MyAsyncTask extends AsyncTask <List <String >,String ,String >
那么对应的我们在提交参数开始执行任务时,就需要传入
List<String>
类型的参数了
List<String> list = new ArrayList<>();
list.add("薯条" );
list.add("汉堡" );
list.add("可乐" );
new MyAsyncTask().execute(list);
在
doInBackground
中获取我们提交的参数
protected String doInBackground (List<String>... params) {
for (String str : params[0 ])
...
return foods;
}
任务执行完毕后,返回一个
String
类型的值,该值即为
onPostExecute
方法的传入参数
protected void onPostExecute (String s)
好了,代码的细节分析完毕,下面我们来看看如何实现任务的进度更新功能
首先我们需要重写
AsyncTask.onProgressUpdate
回调方法,将更新进度UI的操作放在这里面
public