参考:http://www.cnblogs.com/devinzhang/archive/2012/02/13/2350070.html
http://blog.csdn.net/liuhe688/article/details/6532519
1、Android中实现异步任务机制的两种方式:Handler和AsyncTask,Handler模式需要为每一个任务创建一个新的线程,任务完成后通过Handler实例向UI线程发送消息,完成界面的更新,这种方式对于整个过程的控制比较精细,但也是有缺点的,例如代码相对臃肿,在多个任务同时执行时,不易对线程进行精确的控制。关于Handler的相关知识,前面也有所介绍,不清楚的朋友们可以参照一下。
为了简化操作,Android1.5提供了工具类android.os.AsyncTask,它使创建异步任务变得更加简单,不再需要编写任务线程和Handler实例即可完成相同的任务。
2、AsyncTask的定义
public abstract class AsyncTask<Params, Progress, Result> {}
三种泛型类库:
Params:启动任务执行的输入参数
Progress:后台任务执行的进度
Result:后台计算结果的类型
在特定场合下,并不是所有类型都被使用,如果没有被使用,可以用Void类型代替
3、先上代码与结果:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:id="@+id/textView01"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<ProgressBar
android:id="@+id/progressBar02"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
style="?android:attr/progressBarStyleHorizontal"
/>
<Button
android:id="@+id/button03"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="更新progressbar"
/>
</LinearLayout>
MainActivity.java
package com.example.chengvi.myapplication;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
private Button button;
private ProgressBar progressBar;
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button=(Button)findViewById(R.id.button03);
progressBar=(ProgressBar)findViewById(R.id.progressBar02);
textView=(TextView)findViewById(R.id.textView01);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ProgressBarAsyncTask asyncTask=new ProgressBarAsyncTask(textView,progressBar);
asyncTask.execute(100);
}
}
);
}
}
NetOperator.java用于模拟网络环境
package com.example.chengvi.myapplication;
/**
* Created by CHENGVI on 7/21/2016.
*/
public class NetOperator {
public void operator(){
try {
//休眠1秒
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
需要仔细看的代码ProgressBarAsyncTask.java
package com.example.chengvi.myapplication;
import android.os.AsyncTask;
import android.widget.ProgressBar;
import android.widget.TextView;
/**
* Created by CHENGVI on 7/21/2016.
*/
public class ProgressBarAsyncTask extends AsyncTask<Integer,Integer,String> {
private TextView textView;
private ProgressBar progressBar;
public ProgressBarAsyncTask(TextView textView,ProgressBar progressBar){
super();
this.textView=textView;
this.progressBar=progressBar;
}
//params就是AsyncTask第一个参数,调用publishProgress(int)这里的int就是AsyncTask的第二个参数
//返回结果就是AsyncTask的第三个参数
@Override
protected String doInBackground(Integer... params) {
NetOperator netOperator=new NetOperator();
int i=0;
for(i=10;i<=params[0];i+=10){
netOperator.operator();
publishProgress(i); //提示显示进度条,立刻执行onProgressUpdate方法
}
return i+params[0].intValue()+"";
}
//这个方法的参数就是AsyncTask的第三个参数
@Override
protected void onPostExecute(String s) {
textView.setText("异步操作执行结束"+s);
}
@Override
protected void onPreExecute() {
textView.setText("开始执行异步线程");
}
//调用publishProgress之后就执行,参数就是AsyncTask的第二个参数
@Override
protected void onProgressUpdate(Integer... values) {
int value=values[0];
progressBar.setProgress(value);
}
}
执行结果:
点击按钮,开始执行异步任务,首先在主线程做了个标记(“开始执行异步进程”)
执行完成后返回结果:
4、解析:
一个异步任务的执行一般包括以下步骤:
(1)execute(Params…params),执行一个异步任务,需要在主线程中调用此方法,以触发异步任务的执行,当然这个方法只能在主线程中被调用
(2)onPreExecute(),在execute(Params…params)被调用后立即执行,一般用来在执行后台任务前对UI做一些标记
(3)doInBackground(Params…params),在onPreExecute()完成后立即执行,用于执行较为费时的操作,此方法将接收输入参数和返回计算结果。在执行过程中调用publishProgress(Progress…values)来更新进度信息
(4)onProgressUpdate(Progress… values),在调用publishProgress(Progress… values)时,此方法被执行,直接将进度信息更新到UI组件上。
(5)onPostExecute(Result result),当后台操作结束时,此方法将会被调用,计算结果将做为参数传递到此方法中,直接将结果显示到UI组件上。
本例子执行过程:
首先在主线程中调用execute(100)方法,输入参数就是100,于是执行onPreExecute()方法,在UI中做标记,然后立即执行doInBackground(Params…params),这里的params就是我们传入的参数100,在这个方法中:
for(i=10;i<=params[0];i+=10){
netOperator.operator();
publishProgress(i); //提示显示进度条,立刻执行onProgressUpdate方法
}
每一次循环都调用publishProgress(i)方法,这个方法一执行也意味着onProgressUpdate(Progress…Values)的随即执行,这个方法在UI线程中执行,这里的Values其实就是我们AsyncTask的第二个参数,它表示后台执行的进度,于是就在UI中更新进度
当我们的i=110时表示任务执行完成
return i+params[0].intValue()+"";
就返回了AsyncTask的第三个参数,当任务执行完成时会执行nPostExecute(Result result)方法,这个方法的result就是我们doInBackground(Integer…params)返回的结果,所以在任务执行完成后就会像我们前面第三个图一样显示
5、注意
(1)异步任务的实例必须在UI线程中创建。
(2)execute(Params… params)方法必须在UI线程中调用。
(3)不要手动调用onPreExecute(),doInBackground(Params… params),onProgressUpdate(Progress… values),onPostExecute(Result result)这几个方法。
(4)不能在doInBackground(Params… params)中更改UI组件的信息。
(5)一个任务实例只能执行一次,如果执行第二次将会抛出异常。
6、记住这里好几个地方用了(Integer…params)类型的形参,表示的就是这个方法参数个数可变,如果用到params[0]表示第0个参数