Android 为什么要引入异步任务
- Android程序刚启动时,会同时启动一个对应的主线程(Main Thread),这个主线程主要负责处理 与UI相关的事件!有时我们也把他称作UI线程!
- 假如我们在非UI线程中,比如在主线程中new Thread()另外开辟一个线程,然后直接在里面修改UI控件的值; 此时会抛出下述异常: android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views
- 如果我们把耗时的操作都放在UI线程中的话,如果UI线程超过5s没有响应用于请求,那么 这个时候会引发ANR(Application Not Responding)异常,就是应用无响应。
一、为什么要用AsyncTask?
- 官方给我们提供了AsyncTask这个封装好的轻量级异步类,通过几十行的代码就可以完成 我们的异步操作,而且进度可控。
- 实际异步用的最多的地方就是网络操作,图片加载,数据传输等。
注意事项
- Task的实例必须在
UI thread
中创建。- execute方法必须在
UI thread
中调用。- 不要手动的调用
onPreExecute, onProgressUpdate,doInBackground,onPostExecute
这几个方法。- 该Task只能被执行一次,否则多次调用时将会出现异尝。
二、AsyncTask方法讲解:
新建一个类TestAsyncTask
继承AsyncTask
,需要指定三个泛型参数。
public class TestAsyncTask extends AsyncTask<Void, Integer, String>{
}
第一个参数Params
: 开始异步任务执行时传入的参数类型,对应excute()中传递的参数。
第二个参数Progress
: 异步任务执行过程中,返回下载进度值的类型。
第三个参数Result
: 异步任务执行完成后,返回的结果类型,与doInBackground()的返回值类型保持一致。
/**
* 第一个参数Parma: 执行异步任务时传入的参数,即doInBackground方法参数类型。
* 第二个参数Progress: 显示异步任务的进度,选择Integer类型,即onProgressUpdate方法参数类型。
* 第三个参数Result: 异步任务执行完成后,返回的结果类型。即onPostExecute方法的参数类型与doInBackground()的返回值类型保持一致。
* 执行顺序: onPreExecute --> doInBackground --> onProgressUpdate --> onPostExecute
*/
public class TestAsyncTask extends AsyncTask<Void, Integer, String> {
/**
* 通常用于一些初始化操作
*/
@Override
protected void onPreExecute() {
super.onPreExecute();
// 在主线程(UI线程)
// 进行各种初始化
}
/**
* 核心方法,负责执行很耗时的异步任务工作。
*/
@Override
protected String doInBackground(Void... voids) {
// 在子线程
// 在onPreExecute方法执行后马上执行
// 可调用publishProgress() 方法触发onProgressUpdate对UI进行操作
// 比如传递后台任务的进度值,倒计时,下载进度....等
publishProgress(10);
return "String";
}
/**
* 负责回主线程进行UI交互,比如实时刷新显示进度条数据等
* 在doInBackground方法中调用publishProgress方法则触发该方法
*/
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
// 在主线程(UI线程)
// 在这里处理UI更新等
}
/**
* 接收线程任务的执行结果,将执行结果进行回调到主线程
*/
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
// 在主线程(UI线程)
// 异步任务doInBackground执行完毕会自动执行该方法
// 这里onPostExecute方法的参数,和doInBackground的返回值类型必须保持一致
}
/**
* 取消异步任务时触发该方法
*/
@Override
protected void onCancelled(String s) {
super.onCancelled(s);
// 在主线程(UI线程)
// 取消异步任务时触发该方法
}
}
三、如何使用
1、在
doInBackground
方法中实现异步任务。
2、建AsyncTask
子类的实例对象
3、手动调用execute( )
从而执行异步线程任务。
Task
的实例必须在主线程中创建;execute()
方法必须在主线程中调用;- 不要手动的调用
onPreExecute()、onPostExecute(Result)、doInBackground(Param…)、onProgressUpdate(Progress…)
这几个方法;- 每个实例
Task
只能被执行一次,否则多次调用时将会出现异常。所以要进行判断。
四、AsyncTask使用示例(延时线程来模拟文件下载的过程):
布局文件:activity.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MyActivity">
<TextView
android:id="@+id/txttitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<!--设置一个进度条,并且设置为水平方向-->
<ProgressBar
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/pgbar"
style="?android:attr/progressBarStyleHorizontal"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btnupdate"
android:text="更新progressBar"/>
</LinearLayout>
定义一个延时操作,用于模拟下载:
public class DelayOperator {
//延时操作,用来模拟下载
public void delay()
{
try {
Thread.sleep(1000);
}catch (InterruptedException e){
e.printStackTrace();;
}
}
}
自定义AsyncTask:
public class MyAsyncTask extends AsyncTask<Integer,Integer,String> {
private TextView txt;
private ProgressBar pgbar;
public MyAsyncTask(TextView txt,ProgressBar pgbar) {
super();
this.txt = txt;
this.pgbar = pgbar;
}
//该方法运行在UI线程中,可对UI控件进行设置
@Override
protected void onPreExecute() {
txt.setText("开始执行异步线程~");
}
//该方法不运行在UI线程中,主要用于异步操作,通过调用publishProgress()方法
//触发onProgressUpdate对UI进行操作
@Override
protected String doInBackground(Integer... params) {
DelayOperator dop = new DelayOperator();
int i = 0;
for (i = 10;i <= 100;i+=10) {
dop.delay();
publishProgress(i);
}
return i + params[0].intValue() + "";
}
//在doBackground方法中,每次调用publishProgress方法都会触发该方法
//运行在UI线程中,可对UI控件进行操作
@Override
protected void onProgressUpdate(Integer... values) {
int value = values[0];
pgbar.setProgress(value);
}
/**
* 取消异步任务时触发该方法
*/
@Override
protected void onCancelled(String s) {
super.onCancelled(s);
// 在主线程(UI线程)
// 取消异步任务时触发该方法
}
}
MainActivity.java:
public class MyActivity extends ActionBarActivity {
private TextView txttitle;
private ProgressBar pgbar;
private Button btnupdate;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txttitle = (TextView)findViewById(R.id.txttitle);
pgbar = (ProgressBar)findViewById(R.id.pgbar);
btnupdate = (Button)findViewById(R.id.btnupdate);
btnupdate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MyAsyncTask myTask = new MyAsyncTask(txttitle,pgbar);
myTask.execute(1000);
}
});
}
}
网友评论