消息处理机制之Handler

来源:互联网 发布:wbs 协作软件 编辑:程序博客网 时间:2024/04/27 18:31

       

        下面的代码内容来自http://www.cnblogs.com/qingblog/archive/2012/06/27/2566021.html

        什么是handler?handler扮演了往MQ上添加消息和处理消息的角色(只处理由自己发出的消息),即通知MQ它要执行一个任务(sendMessage),并在loop到自己的时候执行该任务(handleMessage),整个过程是异步的。handler创建时会关联一个looper,默认的构造方法将关联当前线程的looper,不过这也是可以set的。默认的构造方法:

<span style="font-size:18px;">[java] view plaincopyprint?public class handler {      final MessageQueue mQueue;  // 关联的MQ         final Looper mLooper;  // 关联的looper         final Callback mCallback;         // 其他属性         public Handler() {          // 没看懂,直接略过,,,           if (FIND_POTENTIAL_LEAKS) {              final Class<? extends Handler> klass = getClass();              if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&                      (klass.getModifiers() & Modifier.STATIC) == 0) {                  Log.w(TAG, "The following Handler class should be static or leaks might occur: " +                      klass.getCanonicalName());              }          }          // 默认将关联当前线程的looper           mLooper = Looper.myLooper();          // looper不能为空,即该默认的构造方法只能在looper线程中使用           if (mLooper == null) {              throw new RuntimeException(                  "Can't create handler inside thread that has not called Looper.prepare()");          }          // 重要!!!直接把关联looper的MQ作为自己的MQ,因此它的消息将发送到关联looper的MQ上           mQueue = mLooper.mQueue;          mCallback = null;      }      // 其他方法   }  public class handler {    final MessageQueue mQueue;  // 关联的MQ    final Looper mLooper;  // 关联的looper    final Callback mCallback;     // 其他属性    public Handler() {        // 没看懂,直接略过,,,        if (FIND_POTENTIAL_LEAKS) {            final Class<? extends Handler> klass = getClass();            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&                    (klass.getModifiers() & Modifier.STATIC) == 0) {                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +                    klass.getCanonicalName());            }        }        // 默认将关联当前线程的looper        mLooper = Looper.myLooper();        // looper不能为空,即该默认的构造方法只能在looper线程中使用        if (mLooper == null) {            throw new RuntimeException(                "Can't create handler inside thread that has not called Looper.prepare()");        }        // 重要!!!直接把关联looper的MQ作为自己的MQ,因此它的消息将发送到关联looper的MQ上        mQueue = mLooper.mQueue;        mCallback = null;    }    // 其他方法}</span>


下面我们就可以为之前的LooperThread类加入Handler:

<span style="font-size:18px;">[java] view plaincopyprint?public class LooperThread extends Thread {      private Handler handler1;        private Handler handler2;        @Override      public void run() {          // 将当前线程初始化为Looper线程           Looper.prepare();          // 实例化两个handler           handler1 = new Handler();          handler2 = new Handler();          // 开始循环处理消息队列           Looper.loop();      }  }  public class LooperThread extends Thread {    private Handler handler1;    private Handler handler2;    @Override    public void run() {        // 将当前线程初始化为Looper线程        Looper.prepare();        // 实例化两个handler        handler1 = new Handler();        handler2 = new Handler();        // 开始循环处理消息队列        Looper.loop();    }}</span>


加入handler后的效果如下图:

可以看到,一个线程可以有多个Handler,但是只能有一个Looper!

Handler发送消息

有了handler之后,我们就可以使用 post(Runnable),postAtTime(Runnable, long),postDelayed(Runnable, long),sendEmptyMessage(int),sendMessage(Message),sendMessageAtTime(Message, long)sendMessageDelayed(Message, long)这些方法向MQ上发送消息了。光看这些API你可能会觉得handler能发两种消息,一种是Runnable对象,一种是message对象,这是直观的理解,但其实post发出的Runnable对象最后都被封装成message对象了,见源码:

<span style="font-size:18px;">[java] view plaincopyprint?<pre name="code" class="java"><span style="color:#000000;">public final boolean post(Runnable r)  {      // 注意getPostMessage(r)将runnable封装成message       return  sendMessageDelayed(getPostMessage(r), 0);  }    private final Message getPostMessage(Runnable r) {         Message m = Message.obtain();  //得到空的message        m.callback = r;  //将runnable设为message的callback        return m;  }    public boolean sendMessageAtTime(Message msg, long uptimeMillis)  {       boolean sent = false;       MessageQueue queue = mQueue;       if (queue != null) {           msg.target = this;  // message的target必须设为该handler!            sent = queue.enqueueMessage(msg, uptimeMillis);       }       else {           RuntimeException e = new RuntimeException(               this + " sendMessageAtTime() called with no mQueue");           Log.w("Looper", e.getMessage(), e);        }        return sent;  }</span>  <pre name="code" class="java"><span style="color:#000000;">public final boolean post(Runnable r){    // 注意getPostMessage(r)将runnable封装成message    return  sendMessageDelayed(getPostMessage(r), 0);}private final Message getPostMessage(Runnable r) {     Message m = Message.obtain();  //得到空的message     m.callback = r;  //将runnable设为message的callback     return m;}public boolean sendMessageAtTime(Message msg, long uptimeMillis){     boolean sent = false;     MessageQueue queue = mQueue;     if (queue != null) {         msg.target = this;  // message的target必须设为该handler!         sent = queue.enqueueMessage(msg, uptimeMillis);     }     else {         RuntimeException e = new RuntimeException(             this + " sendMessageAtTime() called with no mQueue");         Log.w("Looper", e.getMessage(), e);      }      return sent;}</span></span>


 

其他方法就不罗列了,总之通过handler发出的message有如下特点:

1.message.target为该handler对象,这确保了looper执行到该message时能找到处理它的handler,即loop()方法中的关键代码

msg.target.dispatchMessage(msg);

2.post发出的message,其callback为Runnable对象

Handler处理消息

说完了消息的发送,再来看下handler如何处理消息。消息的处理是通过核心方法dispatchMessage(Message msg)与钩子方法handleMessage(Message msg)完成的,见源码

<span style="font-size:18px;">[java] view plaincopyprint?// 处理消息,该方法由looper调用   public void dispatchMessage(Message msg) {      if (msg.callback != null) {          // 如果message设置了callback,即runnable消息,处理callback!           handleCallback(msg);      } else {          // 如果handler本身设置了callback,则执行callback           if (mCallback != null) {               /* 这种方法允许让activity等来实现Handler.Callback接口,避免了自己编写handler重写handleMessage方法。见http://alex-yang-xiansoftware-com.iteye.com/blog/850865 */              if (mCallback.handleMessage(msg)) {                  return;              }          }          // 如果message没有callback,则调用handler的钩子方法handleMessage           handleMessage(msg);      }  }        // 处理runnable消息   private final void handleCallback(Message message) {      message.callback.run();  //直接调用run方法!   }    // 由子类实现的钩子方法   public void handleMessage(Message msg) {  }      // 处理消息,该方法由looper调用    public void dispatchMessage(Message msg) {        if (msg.callback != null) {            // 如果message设置了callback,即runnable消息,处理callback!            handleCallback(msg);        } else {            // 如果handler本身设置了callback,则执行callback            if (mCallback != null) {                 /* 这种方法允许让activity等来实现Handler.Callback接口,避免了自己编写handler重写handleMessage方法。见http://alex-yang-xiansoftware-com.iteye.com/blog/850865 */                if (mCallback.handleMessage(msg)) {                    return;                }            }            // 如果message没有callback,则调用handler的钩子方法handleMessage            handleMessage(msg);        }    }        // 处理runnable消息    private final void handleCallback(Message message) {        message.callback.run();  //直接调用run方法!    }    // 由子类实现的钩子方法    public void handleMessage(Message msg) {    }</span>


 

可以看到,除了handleMessage(Message msg)和Runnable对象的run方法由开发者实现外(实现具体逻辑),handler的内部工作机制对开发者是透明的。这正是handler API设计的精妙之处!

Handler的用处

我在小标题中将handler描述为“异步处理大师”,这归功于Handler拥有下面两个重要的特点:

1.handler可以在任意线程发送消息,这些消息会被添加到关联的MQ上。

 

 

2.handler是在它关联的looper线程中处理消息的。

 

 

 

 

这就解决了android最经典的不能在其他非主线程中更新UI的问题。android的主线程也是一个looper线程(looper在android中运用很广),我们在其中创建的handler默认将关联主线程MQ。因此,利用handler的一个solution就是在activity中创建handler并将其引用传递给worker thread,worker thread执行完任务后使用handler发送消息通知activity更新UI。(过程如图)

 

 

 

  

0 0