android 异步处理AsynTask实例讲解

http://tech.it168.com/a2012/0312/1323/000001323193.shtml


    android提供了一套专门用于异步处理的类。即:AynsTask类。使用这个类可以为耗时程序开辟一个新线程进行处理,处理完时返回。
  其实,AsynTask类就是对Thread类的一个封装,并且加入了一些新的方法。编程时,两者都可以实现同样的功能。本文后面将对AsynTask和Thread进行比较。

1、AsynTask类结构
  asysTask类主要用到的几个内部回调函数有:
doInBackGround()
onPreExecute()
onPostExecute()
onProgressUpdate()
正是这几个回调函数构成了AsynTask类的使用逻辑结构。
   注意:每个AsynTask子类必须至少要重写doInBackGround()方法。
2、回调逻辑关系
  1>主线程调用AsynTask子类实例的execute()方法后,首先会调用onPreExecute()方法。onPreExecute()在主线程中运行,可以用来写一些开始提示代码。
  2>之后启动新线程,调用doInBackground()方法,进行异步数据处理。
  3>处理完毕之后异步线程结束,在主线程中调用onPostExecute()方法。onPostExecute()可以进行一些结束提示处理。
  补充:在doInBackground()方法异步处理的时候,如果希望通知主线程一些数据(如:处理进度)。这时,可以调用publishProgress()方法。这时,主线程会调用AsynTask子类的onProgressUpdate()方法进行处理。
3、各个函数间数据的传递
  通过上面的调用关系,我们就可以大概看出一些数据传递关系。如下:
execute ()向 doInBackground ()传递。
doInBackground() 的返回值会传递给 onPostExecute()
publishProgress() progressUpdate ()传递。
要点:为了调用关系明确及安全,AsynTask类在继承时要传入3个泛型。
第一个泛型对应execute()向doInBackground()的传递类型。
第二个泛型对应doInBackground()的返回类型和传递给onPostExecute()的类型。
第三个泛型对应publishProgress()向progressUpdate()传递的类型。

  传递的数据都是对应类型的数组,数组都是可变长的哦。可以根据具体情况使用。
点击按钮,执行异步操作,执行过程中不断刷新显示内容。
开始界面只有一个按钮.点击按钮后,效果如下:
[Android]异步处理AsynTask实例讲解

可以看到Progress后面的数字不停改变:
[Android]异步处理AsynTask实例讲解

一直到变为100为止。变为100后,界面如下:
[Android]异步处理AsynTask实例讲解

 
 
首先写一个类用来记录线程信息。方便我们跟踪调试。
package com . example . helloAndroid;
import android.util.Log;

public class LogUtils {
    private static final String TAG = "LogUtils";
   
    public static final void thread()
    {
        LogUtils . thread( null);
    }
   
    public static final void thread( String msg ){
        Thread t = Thread . currentThread();
        Log . d( TAG , "<" + t . getName() + ">id: " + t . getId() + ", Priority: " + t . getPriority() + ", Group: " + t . getThreadGroup (). getName()
                + ( msg != null ? ",Msg:" + msg : ""));
    }
}
 接着我们新建一个layout的xml文件。内容如下:
 
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    android:id= "@+id/widget33"
    android:layout_width= "fill_parent"
    android:layout_height= "fill_parent"
    android:orientation= "vertical"
    xmlns:android= "http://schemas.android.com/apk/res/android" >
<Button android:id= "@+id/btnNotify"
        android:layout_width= "wrap_content"
        android:layout_height= "wrap_content"
        android:text= "Start" />
<TextView
    android:id= "@+id/txt1"
    android:layout_width= "fill_parent"
    android:layout_height= "wrap_content"
    android:text= "" />        
</LinearLayout>
现在我们建一个类用来异步处理数据:
package com . example . helloAndroid;

import java.util.List;

import android.app.Activity;
import android.content.Context;
import android.os.AsyncTask;
import android.widget.TextView;

public class Calculator extends AsyncTask < List < Integer >, Integer , Integer > {

    private static final String TAG = "Calculator";
    private Context context;
    private TextView txt1;
    private Integer nResult;
    private Integer nProgress;
   
    public Calculator( Context context)
    {
        this . setContext( context);
    }
   
    public void setContext( Context context)
    {
        this . context = context;
        this . txt1 = ( TextView)(( Activity) this . context ). findViewById( R . id . txt1);
        this . progressUI();
    }
   
    //在处理完毕后,修改界面。只修改了一次界面。
    public void syncUI (){
        //用来看调试信息
        LogUtils . thread( "update ui...");
        //修改界面显示内容
        this . txt1 . setText( "calculate ..." + this . nResult);
    }
   
    @Override
    protected Integer doInBackground( List < Integer >... params)
    {
        //用来看调试信息
        LogUtils . thread( "execute calculating...");
       
        this . nResult = 0;
        Integer p;
        for( int i = 0; i < params [ 0 ]. size(); i ++)
        {
            p = params [ 0 ]. get( i); //p为数字1,2,3,...10
            this . nResult += p . intValue(); //nResult = 1+2+3+...10
            LogUtils . thread( "calculating..." + this . nResult);
            //update progress
            this . publishProgress( 100 * ( i + 1 )/ params [ 0 ]. size());
            try
            {
                Thread . sleep( 1000);
            }
            catch( InterruptedException e)
            {}
        }
        LogUtils . thread( "completed calculator..." + this . nResult);
        return this . nResult;
    }
   
    @Override
    protected void onPreExecute() {
        super . onPreExecute();
        LogUtils . thread( "before calculating...");
        // 在 Main Thread 裡執行,可更新 UI
        this . nProgress = 0;
    }
   
    @Override
    protected void onPostExecute( Integer result)
    {
        super . onPostExecute( result);
        this . nResult = result;
        LogUtils . thread( "calcuted result..." + this . nResult);
        // 在 Main Thread 裡執行,可更新 UI
        this . syncUI();
    }
   
    @Override
    protected void onProgressUpdate( Integer ... values)
    {
        super . onProgressUpdate( values);
        this . nProgress = values [ 0 ];
        LogUtils . thread( "Progress..." + this . nProgress);
        // 在 Main Thread 裡執行,可更新 UI
        this . progressUI();
    }
   
    //在处理过程中,数字不断改变。即不断刷新界面
    private void progressUI()
    {
        //用来看调试信息
        LogUtils . thread( "Update Progress...");
        //修改界面显示内容
        this . txt1 . setText( "Progress:" + this . nProgress);
    }
}
 
然后就是最直观的界面操作了。新建一个Activity。
public class Test Activity extends Activity {
    private Calculator task;
    private String TAG = "AsyncTask";
   
   
    @Override
    public void onCreate( Bundle savedInstanceState) {
        super . onCreate( savedInstanceState);
        setContentView( R . layout . main);
        Log . d( TAG , "onCreate");
        // 重新連線
        this . task = ( Calculator) this . getLastNonConfigurationInstance();
        if( this . task != null)
        {
            Log . d( TAG , "reconnect with asyncTask");
            this . task . setContext( this);
            // 在 Activity 重起過程中已計算完畢,所以要呼叫 AsyncTask 來更新 UI
            if( this . task . getStatus() == AsyncTask . Status . FINISHED)
            {
                this . task . syncUI();
            }
        }
        else
            Log . d( TAG , "task is null");
       
        findViewById( R . id . btnTest ). setOnClickListener( calculatorClick);
}
   
    @Override
    public Object onRetainNonConfigurationInstance (){
       // 保留 Activity 與 AsyncTask 的關聯
        // 供 Activity 因故重起後,可以找回已在執行的 AsyncTask
        return this . task;
    }
   
    private View . OnClickListener calculatorClick = new View . OnClickListener() {
        public void onClick( View v) {
            // TODO Auto-generated method stub
            executeTask();
        }
    };
   
    public void executeTask() {
        Log . d( TAG , "Clicked");
        if( task != null)
        {
            AsyncTask . Status status = task . getStatus();
            Log . d( TAG , "Now status: " + status);
            if( status != AsyncTask . Status . FINISHED)
            {
              //前一計算未完成,不可重起計算
                Log . d( TAG , "continue last calculating ...");
                return;
            }
            //前一計算已完成,可重起計算
            Log . d( TAG , "completed last calculator");
        }
        Log . d( TAG , "new calculator");
        task = new Calculator( this);
        List < Integer > params = new ArrayList < Integer >();
        for( int i = 0; i < 10; i ++)
            params . add( i);
        // 只能呼叫一次 execute(...)
        task . execute( params);
    }
}
 
执行后效果如下:
  [Android]异步处理AsynTask实例讲解
5、总结
  初次看到这个异步调用关系可能觉得很复杂,但其实熟悉了之后会发现这种结构很好用。这种结构将所有的线程通信都封装成回调函数,调用逻辑容易书写。
    尤其是在异步处理结束之后,有回调函数进行收尾处理。
    如果是使用Thread的run()方法,run()结束之后没有返回值。所以必须要自己建立通信机制。
    但是,其实使用Handler+Thread机制其实完全可以替代AsynTask的这种调用机制。只要将Handler对象传给Thread,就可以进行方便的异步处理。且这种MVC模式结构更加明显,方便管理。所以我觉得,使用asynTask还是Handler+Thread结构,个人喜好吧。
 
实际应用可以参考这篇博文: 用AsyncTask从服务器下载文件并显示进

你可能感兴趣的:(android)