天天看点

Android异步通信机制(二)

在工作线程中使用Handler

在UI线程中已经有了Looper,但是在工作线程中要自己实现Looper:

       class LooperThread extends Thread {

                public Handler mHandler;

                   public void run() {

                       Looper.prepare();

                       mHandler = new Handler() {

                            public void handleMessage(Message msg) {

                            // process incoming messages here

                             }

                        };

                        Looper.loop(); //不能在这个后面添加代码,程序是无法运行到这行之后的

                   }

      }

在创建Handler之前,为该线程准备好一个Looper(Looper.prepare),然后让这个Looper跑起来(Looper.loop),抽取Message,这样,Handler才能正常工作。

不是所有的Handler都能更新UI

    Handler处理消息总是在创建Handler的线程里运行。而我们的消息处理中,不乏更新UI的操作,不正确的线程直接更新UI将引发异常。因此,需要时刻关心Handler在哪个线程里创建的。如何更新UI才能不出异常呢?SDK告诉我们,有以下4种方式可以从其它线程访问UI线程(也即线程间通信):

·      Activity.runOnUiThread(Runnable)

·      View.post(Runnable)

·      View.postDelayed(Runnable, long)

·      在UI线程中创建的Handler

其中,重点说一下的是View.post(Runnable)方法。在post(Runnable action)方法里,View获得当前线程(即UI线程)的Handler,然后将action对象post到Handler里。在Handler里,它将传递过来的action对象包装成一个Message(Message的callback为action),然后将其投入UI线程的消息循环中。在 Handler再次处理该Message时,有一条分支(未解释的那条)就是为它所设,直接调用runnable的run方法。而此时,已经路由到UI线程里,因此,我们可以毫无顾虑的来更新UI。

几点小结

·      Handler的处理过程运行在创建Handler的线程里

·      一个Looper对应一个MessageQueue,一个线程对应一个Looper,一个Looper可以对应多个Handler

·      不确定当前线程时,更新UI时尽量调用View.post方法

·      handler应该由处理消息的线程创建。

·      handler与创建它的线程相关联,而且也只与创建它的线程相关联。handler运行在创建它的线程中,所以,如果在handler中进行耗时的操作,会阻塞创建它的线程。

·      Android的线程分为有消息循环的线程和没有消息循环的线程,有消息循环的线程一般都会有一个Looper。主线程(UI线程)就是一个消息循环的线程。

·      Looper.myLooper();      //获得当前的Looper

        Looper.getMainLooper () //获得UI线程的Lopper

·      Handle的初始化函数(构造函数),如果没有参数,那么他就默认使用的是当前的Looper,如果有Looper参数,就是用对应的线程的Looper。

·      如果一个线程中调用Looper.prepare(),那么系统就会自动的为该线程建立一个消息队列,然后调用 Looper.loop();之后就进入了消息循环,这个之后就可以发消息、取消息、和处理消息。

Android提供了一个封装好的带有looper的线程类,即为HandlerThread,具体可参见下面的代码:

public class HandlerThreadActivity extends Activity {

     private static final String TAG = "HandlerThreadActivity";

     private HandlerThread mHandlerThread;

     private MyHandler mMyHandler;

     @Override

     protected void onCreate(Bundle savedInstanceState) {

         // TODO Auto-generated method stub

         super.onCreate(savedInstanceState);

         TextView text = new TextView(this);

         text.setText("HandlerThreadActivity");

         setContentView(text);

         Log.d(TAG, "The main thread id = " +      Thread.currentThread().getId());

         //生成一个HandlerThread对象,实现了使用Looper来处理消息队列的功能,

         //这个类由Android应用程序框架提供

         mHandlerThread = new HandlerThread("handler_thread");

         //在使用HandlerThread的getLooper()方法之前,必须先调用该类的start();

         mHandlerThread.start();

         //即这个Handler是运行在mHandlerThread这个线程中

         mMyHandler = new MyHandler(mHandlerThread.getLooper());

         mMyHandler.sendEmptyMessage(1);

     }

      private class MyHandler extends Handler {

         public MyHandler(Looper looper) {

              super(looper);

         }

         @Override

         public void handleMessage(Message msg) {

              Log.d(TAG, "MyHandler-->handleMessage-->thread id = " + Thread.currentThread().getId());

              super.handleMessage(msg);

         }

     }

}