首先,异步处理消息是为了避免在主线程里一些耗时的操作。我们知道一个ui线程的响应时间是有限的,当主线程长时间得不到响应时程序会报出ANR异常,通常我们要在子线程中处理这些操作,以便让程序可以处理用户的其他事件。今天我就介绍下我用到过的两种处理方式。

一.handler

        我们知道,当一个程序启动时,会启动一个主线程即UI线程。在主线程中会对事件进行分发,当我们要处理一个耗时的操作时如获取互联网资源,加载手机资愿....便不应该在主线程里执行了,不然会造成界面的假死现象,一般5秒钟程序得不到相应便会报出ANR,强制关闭应用程序。所以便要在子线程里执行这些耗时的操作,因为子线程涉及到UI更新,Android主线程是线程不安全的,也就是说,更新UI只能在主线程中更新,子线程中操作是危险的. 这个时候,Handler就出现了来解决这个复杂的问题,由于Handler运行在主线程中(UI线程中),它与子线程可以通过Message对象来传递数据,这个时候,Handler就承担着接受子线程传过来的(子线程用sedMessage()方法传弟)Message对象,(里面包含数据)  , 把这些消息放入主线程队列中,配合主线程进行更新UI。主线程中会默认生成一个Looper对象,不对得循提取MessageQueue里面的消息。在主线程中new Handler并重写起handlemessage方法。

public class MyHandlerActivity extends Activity {
      Button button;
      MyHandler myHandler;
  
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.handlertest);
  
          button = (Button) findViewById(R.id.button);
          myHandler = new MyHandler();
          // 当创建一个新的Handler实例时, 它会绑定到当前线程和消息的队列中,开始分发数据
          // Handler有两个作用, (1) : 定时执行Message和Runnalbe 对象
          // (2): 让一个动作,在不同的线程中执行.
  
          // 它安排消息,用以下方法
          // post(Runnable)
          // postAtTime(Runnable,long)
          // postDelayed(Runnable,long)
          // sendEmptyMessage(int)
          // sendMessage(Message);
          // sendMessageAtTime(Message,long)
          // sendMessageDelayed(Message,long)
        
          // 以上方法以 post开头的允许你处理Runnable对象
          //sendMessage()允许你处理Message对象(Message里可以包含数据,)
  
          MyThread m = new MyThread();
          new Thread(m).start();
      }
  
      /**
      * 接受消息,处理消息 ,此Handler会与当前主线程一块运行
      * */
  
      class MyHandler extends Handler {
          public MyHandler() {
          }
  
          public MyHandler(Looper L) {
              super(L);
          }
  
          // 子类必须重写此方法,接受数据
          @Override
          public void handleMessage(Message msg) {
              // TODO Auto-generated method stub
              Log.d("MyHandler", "handleMessage......");
              super.handleMessage(msg);
              // 此处可以更新UI
              Bundle b = msg.getData();
              String color = b.getString("color");
              MyHandlerActivity.this.button.append(color);
  
          }
      }
  
      class MyThread implements Runnable {
          public void run() {
  
              try {
                  Thread.sleep(10000);
              } catch (InterruptedException e) {
                  // TODO Auto-generated catch block
                  e.printStackTrace();
              }
  
              Log.d("thread.......", "mThread........");
              Message msg = new Message();
              Bundle b = new Bundle();// 存放数据
              b.putString("color", "我的");
              msg.setData(b);
  
              MyHandlerActivity.this.myHandler.sendMessage(msg); // 向Handler发送消息,更新UI
  
          }
      }

二.AsyncTask

Android 1.5已经提供了一个工具类——AsyncTask,使用AsyncTask可以是创建需要与用户界面交互的长时间运行的任务变得更简单。

AsyncTask 是一个抽象类,他提供了三个泛型参数,详细如下

         AsyncTask的三个泛型参数

1.       Param 任务执行需要的参数

2.       Progress 后台任务执行的进度单位数据

3.       Result 后台任务执行最终返回的数据类型

注意:在设置参数时通畅是:String …params,这表示方法可以有0个或多个String类型的参数;不使用参数时可设置为 Void…
       
使用AsyncTask类,必须重载AsyncTask的四个方法(至少重载一个)。详细如下:

          AsyncTask的四个方法

1.       onPreExecute() 这个方法主要用于执行一些预处理操作,它运行于UI线程,一般用来为后台任务做一些准备工作,如在界面上显示一个进度条。
3.       doProgressUpdate(Progress…) 这个方法运行于UI线程。如果在doInBackground(Params…)中使用了publishProgress(Progress…),UI线程就会调用这个方法对进度条控件的进度值进行控制。

4.       onPostExecute(Result) 这个方法也运行于UI线程,在doInBackground(Params…)方法执行后调用,该方法用于处理后台任务执行后返回的结果。

实例解析

以移动护理中的病人列表异步任务处理为例:
 

@Override
       protected void onPreExecute() {
           super.onPreExecute();
           // 获取Wifi网络连接状态
           isNetWorkConnected = NetWorkActivity
                  .isNetworkAvailable(PatiListActivity.this);
           if (isNetWorkConnected)
              // 弹出提示对话框
              mDialog.show();
    }

onPreExecute()方法主要用于检查网络连接是否成功,如果成功则弹出进度条对话框。该方法运行于UI线程。

@Override
       protected Object doInBackground(Object... arg0) {
           if (isNetWorkConnected) {
              // 获取病人列表数据
              patientList = getPatiList();
           }
           return null;
       }

doInBackground()方法主要进行网络访问和XML解析,以获取病人列表数据,它运行于后台线程。这里没有调用 publishProgress() 方法,因为我们的进度条不需要显示百分比,因此我们也没必要重载doProgressUpdate(Progress…)方法。

@Override
       protected void onPostExecute(Object result) {
           super.onPostExecute(result);
           if (isNetWorkConnected) {
              try {
                  // 加载页面控件
                  drawPage();
                  // 关闭提示对话框
                  mDialog.dismiss();
              } catch (Exception e) {
                  e.printStackTrace();
                  Toast.makeText(PatiListActivity.this, errorMsg,
                         Toast.LENGTH_SHORT).show();
              }
           }
       }

OnPostExecute()运行于UI线程,通过doInBackgroud()方法获取的病人列表来加载页面控件,完成后关闭对话框。至此,异步任务处理整个过程结束。

2.       doInBackground() 这个方法运行在后台线程中,主要负责执行那些很耗时的操作,如移动护理系统中的网络连接、解析XML等操作。这个方法在onPreExecute()方法后执行,该方法是抽象方法,也是AsyncTask的关键,所以该方法必须重载。另外,在这个方法中可以使用 publishProgress(Progress…)来改变当前的进度值。