1、AsyncTask简介
AsyncTask允许你能够很容易并且正确地访问UI线程。它能够让你轻松地执行后台操作并且把结果返回给UI线程,它的目标是代替Thread和Handler来执行轻量化地跨线程操作。
2、使用场景
Android系统禁止任何主线程的网络连接行为,即时强行为之,Android也会抛出NetworkMainThreadException异常;同时,如果我们在主线程中执行长时间的耗时任务,在等待响应期间,用户界面毫无反应,这样很可能导致应用无响应(Application Not Responding, ANR)现象发生。因此,我们可以将网络连接等耗时任务放到后台线程中去执行,执行完之后再回到主线程中将结果展示出来。怎样使用后台线程最容易?答案是使用AsyncTask。与Thread和Handler相比,AsyncTask是如此的简单
3.AsyncTask使用简介
1)如果获取AsyncTask
AsyncTask是一个抽象类,我们使用时需要继承它,然后实现它的抽象方法。AsyncTask强制要求我们实现的只有一个方法,即doInBackground(),通过名称就可以知道,可以把我们想要在后台执行的操作放到该方法中。一个最简单的AsyncTask实现如下
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new AsyncTaskImpl().execute();
}
private class AsyncTaskImpl extends AsyncTask<Void, Void, Void>{
@Override
protected Void doInBackground(Void... params) {
return null;
}
}
}
2)参数解析
从上面的创建Async的过程中,我们看到AsyncTask实现时需要传入三个类型参数,下面我们一一解析一下
a、第一个参数
有时候我们执行的后台操作可能需要我们传入一些参数才能正常运行,在这种情况下,我们就可以使用第一个参数为后台操作指导参数的类型,我们暂时称它为执行参数。既然是传递给后台操作的参数类型,可想而知,doInBackground()方法的形参也会作出相应的变化,此时doInBackground()方法的形参就变成我们制定类型的变长参数了。一个带执行参数的AsyncTask实现如下:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new AsyncTaskImpl().execute("AAAA","BBBB","CCCC");
}
private class AsyncTaskImpl extends AsyncTask<String, Void, Void>{
@Override
protected Void doInBackground(String... params) {
for (String s : params){
Log.d(TAG, s);
}
return null;
}
}
}
同时我们打印了在doInBackground()方法获取到的参数,控制台输出如下:
06-26 16:19:11.432 12416-12448/com.android.yanghuaan.asynctaskdemo D/MainActivity: AAAA
06-26 16:19:11.432 12416-12448/com.android.yanghuaan.asynctaskdemo D/MainActivity: BBBB
06-26 16:19:11.432 12416-12448/com.android.yanghuaan.asynctaskdemo D/MainActivity: CCCC
b、第三个参数
为什么直接跳过第二个参数介绍第三个参数?以为我觉得第三个参数对我们来说更重要或者说更实用,第二个参数后面再介绍。我们执行后台操作,很多情况下是希望从后台操作中获取我们想要的数据,这正是第三个参数要干的事情:指定返回参数类型。看到这里,不尽有人想问,我们从哪里获得返回的数据呢?其实,AsyncTask还有一个方法:onPostExecute(),这个方法只提供了空的实现,我们需要从后台操作中获得返回的数据,就必须覆盖这个方法。值得注意的是,这个方法的是在主线程中执行的,因此我们可以在这个方法中做主线程可以才能做的事情,比如修改UI元素等。一个简单的示例如下:
public class MainActivity extends AppCompatActivity {
private TextView mTextView;
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView) findViewById(R.id.text_view);
mTextView.setText("helloWorld");
new AsyncTaskImpl().execute("AAAA","BBBB","CCCC");
}
private class AsyncTaskImpl extends AsyncTask<String, Void, List<String>>{
@Override
protected List<String> doInBackground(String... params) {
List<String> result = new ArrayList<>();
for (int i = params.length - 1; i >= 0; i --){
result.add(params[i]);
}
return result;
}
@Override
protected void onPostExecute(List<String> strings) {
mTextView.setText("in onPostExecute method");
for (String s : strings){
Log.d(TAG, s);
}
}
}
}
控制台输出如下:
06-26 16:44:25.179 8647-8647/? D/MainActivity: CCCC
06-26 16:44:25.180 8647-8647/? D/MainActivity: BBBB
06-26 16:44:25.180 8647-8647/? D/MainActivity: AAAA
同时可以看到屏幕上的显示的内容由默认的helloWorld变为in onPostExecute method。
c、第二个参数
如果说我们想要知道后台操作进行的进程如何,该怎么办呢?第二个参数就可以用来指定发送进度更新需要的数据类型。这个参数与Async的另一个方法onProgressUpdate()有关,即该参数用来指定此方法的形参,并且这个方法也是在主线程中执行的,可以用来修改UI元素,最常见的就是设置进度条进度。
值得注意的是,进度更新通常放生在执行后台线程中。问题是后台线程无法完成必要的UI更新。因此AsyncTask提供了publishProgress()和onProgressUpdate()方法。其工作方式是:从doInBackground()方法中调用publishProgress()方法,这样onProgressUpdate()方法就能在主线程中更新UI了,即传入publishProgress()方法的参数最终传递给了onProgressUpdate()方法,而第二个参数就是用来指定此参数的类型。一个完整的示例如下:
public class MainActivity extends AppCompatActivity {
private TextView mTextView;
private ProgressBar mProgressBar;
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView) findViewById(R.id.text_view);
mTextView.setText("helloWorld");
mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);
mProgressBar.setProgress(0);
new AsyncTaskImpl().execute("AAAA","BBBB","CCCC");
}
private class AsyncTaskImpl extends AsyncTask<String, Integer, List<String>>{
@Override
protected List<String> doInBackground(String... params) {
List<String> result = new ArrayList<>();
for (int i = params.length - 1; i >= 0; i --){
result.add(params[i]);
}
for (int i = 1; i <= 100; i ++){
try{
Thread.sleep(100);
}catch (InterruptedException ie){
ie.printStackTrace();
}
publishProgress(i);
}
return result;
}
@Override
protected void onPostExecute(List<String> strings) {
for (String s : strings){
Log.d(TAG, s);
}
}
@Override
protected void onProgressUpdate(Integer... values) {
int progress = values[0];
mProgressBar.setProgress(progress);
if (progress == 100){
mTextView.setText("Complete.");
}
}
}
}
可以看到屏幕上的进度条逐渐增加并且最终默认的helloWorld变为Complete。