Android之AsyncTask的使用
为了解决新线程不能更新UI组件的问题,Android提供了如下几种解决方案
1.使用Handler实现线程间的通信
2.Activity.runOnUiThread(Runnable)
3.View.post()
4.View.postDelayed(Runnable,long)
这几种方式有时候会导致编程显得繁琐,而异步任务(AsyncTask)可以进一步
简化操作,不需要借助额外的hanlder即可实现。当我们通过线程执行耗时任务,并且在执行完任务以后可能会对UI进行更新,一般我们都会使用Handler来更新UI,但是如果多个任务同时执行时则会显得代码臃肿,Anroid提供了AsyncTask,他使得异步任务实现起来更加简单,代码简洁。
public abstract class AsyncTask<Params, Progress, Result> {}
AsyncTack是一个抽象的泛类型,通常被用来继承,它有三个泛型参数分别是Params,Progress,Result
- Params:指定任务执行的输入参数的类型
- Progress:是后台任务完成得进度值的类型
- Result:执行完成任务后返回结果的类型。
如果不需要某个参数,可以设置为void。
AsyncTask中的四个核心方法:
- 1.onPreExecute():在主线程中执行,一般在任务执行前做准备工作,比如对
UI进行一些标记。如初始化控件的一些参数。 - 2.doInBackground(Params…params):在线程池中执行,在onPreExecute()方法执行完
以后运行,用来完成角为耗时的操作,在执行过程中可以调用publishProgress(Progress…values)
来更新进度的信息 - 3.onProgressUpdate(Progress values):在主线程中执行,当调用publishProgress(Progress values)时,此方法会将进度更新到UI组件上。
- 4.onPostExecute():在主线程中执行,当后台任务执行完毕以后,他会被执行
doInBackground方法得到的结果就是返回的result的值,此方法一般做任务执行
后的首尾工作,比如更新UI和数据。
重写上述几个方法后,调用AsyncTack子类的实例的execute()方法开始执行耗时任务
使用AsyncTask时必须遵循下列规则:
- 1.必须在UI线程中创建AsyncTask
- 2.必须在UI线程中调用AsyncTask的execute()方法
- 3.AsyncTask的onPreEcexute(),onPostExecute()等几个方法不应该由程序员代码调用
而应该由系统调用 - 4.每个AsyncTask只能被调用一次,多次调用会引发异常
使用AsyncTask执行下载任务的demo,布局代码如下
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Activity.AsyncTaskActivity">
<ProgressBar
style="@android:style/Widget.ProgressBar.Horizontal"
android:id="@+id/progressbar"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:text="下载内容"
android:id="@+id/show"
android:textSize="18sp"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/id_btn"
android:textSize="18sp"
android:text="开始下载"
android:onClick="downLoad"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
java代码如下:
import android.content.Context;
import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.example.yang.toolbar.R;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
public class AsyncTaskActivity extends AppCompatActivity {
private TextView show;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_async_task);
show=findViewById(R.id.show);
}
public void downLoad(View view) throws MalformedURLException {
DownLoad task=new DownLoad(this, (ProgressBar) findViewById(R.id.progressbar));
task.execute(new URL("http://www.baidu.com"));
}
class DownLoad extends AsyncTask<URL,Integer,String>{
private ProgressBar progressBar;
int hasRead=0;
Context context;
//构造函数如下
public DownLoad(Context context,ProgressBar progressBar){
this.context=context;
this.progressBar=progressBar;
}
//点击后首先执行onPreExecute()进行准备工作,控件的初始化等,第二步执行doInBackGround()方法,
//在该方法内调用了publishProgress()方法来更新任务的执行进度
//调用publishProgress()会触发onProgressUpdate完成对UI进度条的更新
//当doInBackground()方法完成后,系统会自动调用onPostExecute()方法,并将doInBackground()方法的返回值
//传递给该方法
@Override
protected String doInBackground(URL... urls) {
StringBuilder builder=new StringBuilder();
try{
//获取输入流
URLConnection conn=urls[0].openConnection();
BufferedReader br=new BufferedReader(new InputStreamReader(
conn.getInputStream(),"utf-8"));
String line=null;
//读数据
while ((line=br.readLine())!=null){
builder.append(line+"\n");
hasRead++;
publishProgress(hasRead);
//更新UI
}
//返回数据
return builder.toString();
}catch (Exception e){
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(String s) {
//什么时候被调用?当在doInBackground中调用publishProgress时调用
show.setText(s);
progressBar.setVisibility(View.INVISIBLE);
}
@Override
protected void onPreExecute() {
//给UI控件设置参数等一些工作
progressBar.setVisibility(View.VISIBLE);
progressBar.setProgress(0);
progressBar.setMax(120);
}
@Override
protected void onProgressUpdate(Integer... values) {
show.setText("已经读取了【"+values[0]+"】行!");
progressBar.setProgress(values[0]);
}
}
}
代码的执行流程
1.点击后首先执行onPreExecute()准备工作控件的初始化等,第二步执行doInBackGround()方法。
2.在该方法内调用了publishProgress()方法来更新任务的执行进度。
3.调用publishProgress()会触发onProgressUpdate完成对UI进度条的更新。
4.当doInBackground()方法完成后,系统会自动调用onPostExecute()方法,并将doInBackground()方法的返回值传递给该方法。