AsyncTask初体验

在Android中,由于系统对UI线程的控制使得我们很难去操控前台界面的变化。

虽然我们可以使用诸如handle通过发送消息的方式让前台UI实现“自我更新”,但是对于一些大型项目来说,把过多的时间花费在对线程的控制上是很不明智的。Google当然也想到了这一点,所以就出现了AsyncTask这样的东西。

AsyncTask是Google为Android提供的一个多线程工具类。它的好处在于你不需要再像以前那样为了修改前台UI而编写一个后台线程,并且不需要添加条件以终止线程,甚至能直接在代码段里控制UI线程。如果需要做游戏、以及一些经常操作前台UI的程序,个人感觉非常实用。

想要使用AsyncTask必须要做以下的几件事情:

  1. 创建一个继承自AsyncTask的子类。
  2. 在子类中override AsyncTask中原有的部分函数。
  3. 在你需要的时候执行execute()函数,系统会自动将其变成一个在后台运行的线程,并且能直接修改UI。

那么究竟该如何使用呢?

首先,AsyncTask是一个用来被继承的泛型类,分别接受三个泛型参数 <T1,T2,T3>:T1,处理任务的信息类型。T2,用于更新进度、在任务间传递的信息类型。T3,任务结束时传递到后面代码的信息类型。

然后,我们有5个方法能够被我们override:

/*在execute之前执行,用来做准备工作(清理画布、创建画笔等)*/
protected void onPreExecute();  
/*AsyncTask会在后台线程调用这个函数,并且是有机会就调用,直到系统判断这个函数已经执行完,函数接受处理任务时所需的信息作为参数,返回执行后的结果并且传递给onPostExecute。*/
protected T3 doInBackground(T1.. params);  
/*如果在doInBackground方法中调用了publishProgress(T2)方法,则可以复写这个方法。每次调用了publishProgress(T2)后将会调用该方法。并且传递T2。该方法一般用于修改前台UI元素中用以表示进度的组件、或者用来控制后台线程进度的对象。*/
protected void onProgressUpdate(T2... values);  
/*在程序判断doInBackground没有必要再执行的时候,这个函数就会被调用,并且传递进最后一次执行doInBackground返回的内容。该函数通常用于收尾工作*/
protected void onPostExecute(T3 result);  
/*在调用了Async中的cancel函数之后会激发这个函数。用来进行一些收尾工作。*/
protected void onCancelled();  

上面的说的听起来很复杂,就先让我通过一个例子来解释清楚吧。

例如我们想要设计一个用来显示更新的进度条。这个是Handle用法的经典例子。但是在这里我们用到非常方便的AsyncTask。

先创建一个AsyncTask<T1,T2,T3>的子类,并且override必要的几个函数。

紧接着我们需要创建一个该内部类的对象,并且执行其execute()方法。这样AsyncTask就会创建一个后台线程,并且能够修改到前台的UI了。

package cn.Friskit;


import android.app.Activity;  
import android.os.AsyncTask;  
import android.os.Bundle;  
import android.os.SystemClock;  
import android.widget.ProgressBar;  
import android.widget.Toast;

public class AsyncDemoActivity extends Activity {  
    ProgressBar bar;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        bar = (ProgressBar)findViewById(R.id.progress);
        /*创建一个ProgressBarUpdateTask的实例,并且执行execute()函数*/
        new ProgressBarUpdateTask().execute();
    }

    /*本地类ProgressBarUpdateTask是一个AsyncTask的子类,三个泛型参数分别是Void(本例不需要处理信息),Integer(进度条进度用数字表示),Void类型(不需要返回执行信息)。*/
    class ProgressBarUpdateTask extends AsyncTask<Void,Integer,Void>{
        /*在execute执行之前被自动执行的回调函数*/
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }

        /*后台一有机会就会执行这个函数。这个函数接受T1(此为Void)作为参数,可以处理T1类型传递进来的数据。
         * 如果doInBackground中执行了publishProgress函数,则需要将一个用来控制进度的变量T2(此为Integer传递进去)。
         * 同时系统会回调onProgressUpdate(T2)*/
        @Override
        protected Void doInBackground(Void... params) {
            while(bar.getProgress()!=100){
                publishProgress(new Integer(5));
                SystemClock.sleep(500);
            }
            return null;
        }

        /*当doInBackground中执行了publishProgress函数,则此函数会被调用,并且接受一个T2(此例为Integer)作为参数。
         * 一般用来表示进度更新*/
        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            bar.setProgress(bar.getProgress()+values[0]);
        }

        /*程序执行完毕之后执行的收尾函数*/
        @Override
        protected void onPostExecute(Void result) {
            super.onPostExecute(result);
            Toast.makeText(AsyncDemoActivity.this, "Done!!", Toast.LENGTH_LONG).show();
        }

        /*如果调用了AsyncTask的Cancel函数,则该函数会被回调*/
        @Override
        protected void onCancelled() {
            super.onCancelled();
        }
    }
}

上面就是AsyncTask的一个使用实例。该实例运行后就是一个进度条缓慢地在增长。在完成后会弹出一个Toast。

通过这个例子,可以看到这个工具类有多强大。它能将程序员从繁琐的后台线程编制之中解救出来!如果你需要做游戏或者其他一些需要更新前台UI的程序的话,可以多用用这个!

教程到此结束。。

Friskit

继续阅读此作者的更多文章