消息处理机制之Handler

本文深入解析了Android中的Handler机制,包括其在异步处理、消息传递、线程间通信等方面的作用,并通过实例展示了如何在实际项目中应用Handler进行消息的发送与接收。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

       

        下面的代码内容来自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。(过程如图)

 

 

 

  

转载于:https://www.cnblogs.com/james-zhan/p/6581414.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值