AsyncTask
AsyncTask 是Android为我们提供的另一种简单的异步线程机制。它可以比较方便的让我们的UI线程和后台线程并发,可以让用户执行一些需要长时间等待的程序时,用户体验不会因此而下降。
首先AsyncTask是一个抽象类,我们要使用它,必须写一个类来继承它。它有三个泛型参数,Param,Progress,Result,分别表示任务执行的参数,后台程序执行的进度和后台程序执行的结果。如果不提供参数,或者不使用进度,或者不需要结果,可以传入Void。同时,父类AsyncTask定义了若干方法,其中doInBackground(Params...)是抽象方法,所以在子类中必须实现,这个方法是和UI线程脱离的,即和UI线程异步的。
另外还有3个方法,分别是:
onPreExecute(),这个方法归属于UI线程,它执行于DoInBackgroud()之前,可以用作一些预处理,等会儿在例子中,我们使用这个方法来预处理进度条和百分比的显示初始化。
onPostExecute(Result),这个方法也归属于UI线程,他执行于doInBackgroud()之后,用于传递这个后台任务的执行结果。
onProgressUpdate(Progress...),这个方法同样归属于UI线程,它的执行与否,取决于DoInBackgroud()方法中是否使用了publishProgress方法,每次执行publishProgress方法,onProgressUpdate(Progress...)就会被调用一次。在这个方法中,通过publishProgress方法传来的进度信息,来更新UI信息。
需要注意的是,AsyncTask的子类的一个实例的生命周期从onPreExecute()开始,到onPostExecute(Result)结束,该实例之后就变成了垃圾,没用了。如果需要使用,就必须重新创建一个实例。
下面来看一个例子,这个例子实现的是一个进度条,从点击”Start”按钮开始进度条滚动。
布局文件很简单,一个开始按钮,一个进度条,和一个显示进度百分比的TextView
布局文件如下:
 
  
  1. <?xmlversion="1.0"encoding="utf-8"?>

  2. <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"

  3. android:orientation="vertical"android:layout_width="fill_parent"

  4. android:layout_height="fill_parent">

  5. <Button

  6. android:id="@+id/start"

  7. android:layout_width="fill_parent"

  8. android:layout_height="wrap_content"

  9. android:text="Start"

  10. />

  11. <ProgressBar

  12. android:id="@+id/bar"

  13. android:layout_width="200dp"

  14. android:layout_height="wrap_content"

  15. style="?android:attr/progressBarStyleHorizontal"

  16. android:max="100"

  17. android:visibility="gone"

  18. />

  19. <TextView

  20. android:id="@+id/percent"

  21. android:layout_width="wrap_content"

  22. android:layout_height="wrap_content"

  23. android:textSize="10dp"

  24. android:text="0%"

  25. android:visibility="gone"

  26. android:layout_marginLeft="90dp"

  27. android:layout_marginTop="-18dp"

  28. android:textColor="#000"

  29. />

  30. </LinearLayout>

接下来看Java代码:
 
  
  1. import android.app.Activity;

  2. import android.os.AsyncTask;

  3. import android.os.Bundle;

  4. import android.view.View;

  5. import android.view.View.OnClickListener;

  6. import android.widget.Button;

  7. import android.widget.ProgressBar;

  8. import android.widget.TextView;

  9. publicclass AsyncTaskDemoActivity extends Activity {

  10. private ProgressBar bar = null;

  11. private Button start = null;

  12. private TextView percent = null;

  13. /** Called when the activity is first created. */

  14. @Override

  15. publicvoid onCreate(Bundle savedInstanceState) {

  16. super.onCreate(savedInstanceState);

  17. setContentView(R.layout.main);

  18. start = (Button)findViewById(R.id.start); //Start按钮

  19. start.setOnClickListener(new OnClickListener() {

  20. @Override

  21. publicvoid onClick(View arg0) {

  22. // TODO Auto-generated method stub

  23. SubAsyncTask sat = new SubAsyncTask(); //创建AsyncTask子类的实例

  24. sat.execute(); //启动线程

  25. }

  26. });

  27. }

  28. publicclass SubAsyncTask extends AsyncTask<Object, Integer, String>{

  29. @Override

  30. protectedvoid onPreExecute() {

  31. // TODO Auto-generated method stub

  32. System.out.println("Thread in onPreExecute---->"+Thread.currentThread().getName());

  33. //在预处理方法中定义进度条和百分比文本

  34. bar = (ProgressBar)findViewById(R.id.bar);

  35. bar.setVisibility(View.VISIBLE);

  36. percent = (TextView)findViewById(R.id.percent);

  37. percent.setVisibility(View.VISIBLE);

  38. super.onPreExecute();

  39. }

  40. @Override

  41. protected String doInBackground(Object... arg0) {

  42. // TODO Auto-generated method stub

  43. //每50ms执行一次publishProgress

  44. for (int j = 0; j <=100; j+=10) {

  45. System.out.println("Thread in doInBackground---->"+Thread.currentThread().getName());

  46. publishProgress(j);

  47. try {

  48. Thread.sleep(50);

  49. } catch (InterruptedException e) {

  50. // TODO Auto-generated catch block

  51. e.printStackTrace();

  52. }

  53. }

  54. returnnull;

  55. }

  56. @Override

  57. protectedvoid onProgressUpdate(Integer... values) {

  58. // TODO Auto-generated method stub

  59. //每执行一次publishProgress就需要执行一次这个函数,在这个函数里变化进度条信息

  60. System.out.println("Thread in onProgressUpdate---->"+Thread.currentThread().getName());

  61. bar.setProgress(values[0]);

  62. percent.setText(values[0]+"%");

  63. }

  64. @Override

  65. protectedvoid onPostExecute(String result) {

  66. // TODO Auto-generated method stub

  67. //doInBackground方法执行完后,执行这个函数,用来提交结果

  68. bar.setVisibility(View.GONE);

  69. percent.setVisibility(View.GONE);

  70. System.out.println("Thread in onPostExecute---->"+Thread.currentThread().getName());

  71. super.onPostExecute(result);

  72. }

  73. }

  74. }

从代码看出,我们并没有将UI上得进度条控件和文本控件在onCreate函数中创建,而是只创建了一个开始Button,然后用匿名内部类为该Button绑定了一个事件监听器。在监听器内部,我们实例化了SubAsyncTask,SubAsyncTask是AsyncTask的子类,然后调用execute()方法来启动它。
重要的我们看SubAsyncTask子类的实现。它继承了AsyncTask类并且重载了四个方法,也就是上面我提到的那四个方法。窝在每个方法内都设置了输出语句,查看当前的方法是哪个线程在执行。
作为预处理方法,我在onPreExecute()方法中定义了进度条和百分比的TextView。当该函数执行完毕后,就开始执行doInBackground方法,在此方法中,我每隔50ms就执行一次publishProgress方法,这就意味着相应的,会有一个onProgressUpdate方法被调用,在onProgressUpdate方法中,我对进度条和进度百分比进行改变设置。当doInBackground方法运行完毕后,会自动执行onPostExecute方法,来提交执行的结果。
下图为运行的效果图:

205739934.png

下图是每隔50ms,在Logcat中打印出来的记录,可以看出有两个线程在运行,一个是主线程,也就是UI线程,另一个是AsyncTask的线程。再看他们的输出顺序,可以发现,在更新进度条阶段,并不是规律的主线程与AsyncTask线程交替出现,也就说明,当AsyncTask线程更新进度条信息后,并没有等待UI线程更新UI,而是继续往下执行了,这也进一步体现了异步的特点。

205806401.png

如果将时间间隔改的更小,这种异步的输出就更明显了,下图是将时间间隔改为10ms的Logcat输出。

205846913.png

AsyncTask比较方便的为我们提供了异步机制,可以有效的处理一些简单的UI线程与后台线程的异步实现和交互。

附件是示例代码,仅供参考。

如果我的文章给与了你帮助,就不妨请我喝杯咖啡吧,点击-> btn-index.png