Android之handler消息处理机制详解

handler消息处理机制

handler是什么?

​ Handler是一个在消息处理机制中负责发送和处理消息的类,是消息处理的关键。

消息处理涉及的主要类

  • Handler:负责发送消息和处理消息
  • Looper:内置一个死循环,可以不断的取出消息并通知handler处理消息,是handler起作用的基础
  • Message:消息实体类
  • MessageQueue:消息队列,负责存储消息

消息处理的基本原理

在这里插入图片描述

Thread、Handler、Lopper、MessageQueue对应关系

​ 一个Lopper对应一个MessageQueue,因为Looper内置了一个消息队列。

​ 一个Thread只能有一个Lopper。

​ 一个Handler对象对应一个Thread和Thread的消息队列(但是一个Thread内可以有多个Handler)。当你创建一个Handler时,它就和Thread的消息队列绑定在一起。

特别注意:Handler虽然和Looper是一一对应的,但是Hanlder本身并不含有Looper,Looper是通过线程内部的存储类存储在Thread里的的,而Looper内置了一个消息队列。

消息传递基本思想

​ 在线程B中获取属于线程A的handler,在B中创建的message可以通过调用handler.sendmessage(message对象)将消息添加到A线程的消息队列中去,A线程的Looper循环会取出消息并通知hanlder去处理消息,调用回调函数handler.handleMessage(用户一般要重写此方法)去处理消息。所以就实现了把B线程的数据封装到message中传递给线程A,通过线程A中重写handler的handleMessage方法在线程A中处理消息。

handler消息处理机制能做什么?

  • 实现消息的异步处理,例如将子线程的数据通过Message传递到主线程中
  • 一般来说UI控件只能在主线程中更新,但是在子线程中可以通过handler更新UI

Handler

​ Handler用于发送、处理消息,Handler本身不含有message,而message中有个target属性(hanlder类型),用于此条标识消息要由哪个handler去处理。

​ Handler有多个构造函数,但本质上都是外部传入一个Looper,Handler属于哪个现场取决于传入Looper属于哪个线程。

post(runable)				//发送消息,Runnable是消息回调,经过消息循环引发消息回调函数执行;
    
sendMessage(message)		//发送消息,经过消息循环派发消息处理函数中处理消息;

dispatchMessage(messsage)   //派发消息,主要作用就是根据情况调用回调函数。
                     //若是post或带有回调函数则执行回调函数,否则执行消息处理函数Handler的handleMessage(通常派生类写)。

​ sendMessage和post两种发消息的本质是一样的,都是发送一个Message。只是post(runable r)方法发送的是一个callback属性为r的message,两个方法发出的消息在loop取出后,最终都会交到dispatchMessage处理。

handler消息处理的流程图

在这里插入图片描述

dispatchMessage(派发消息)源码分析

​ 从代码中可以看到message本身有一Runable接口,只有它为空则执行handlemessage。

​ hanlder本身包含一个回调函数handlemessage,它本身又包含一个callback接口,接口里面又是一个handkemessage回调函数,到底执行哪个handlemessage就在dispatchMessage中判断,判断优先级是:消息回调 > handler的callback的回调 > handler本身回调

    public void dispatchMessage(@NonNull Message msg) {
        if (msg.callback != null) {		//首先判断消息本身Runable是否为空,不为空就只执行消息的callback(Runable类型)
            handleCallback(msg);
        } else {
            if (mCallback != null) {	//如果handler的callback接口不为空,则执行hanlder的callback的回调函数
                if (mCallback.handleMessage(msg)) {	
                    return;				//再如果callback的回调函数中返true,则不执行hanlder本身的回调函数
                }
            }
            handleMessage(msg);			//当消息的callback为空且handler的callback也为空或者,才执行handler本身的回调函										数
        }
    }

Looper

​ 实现Thread的消息循环和消息派发,缺省情况下Thread是没有这个消息循环的,即没有Looper;

​ 需要主动去创建(调用Lopper.prepare()),然后启动消息循环(调用Lopper.loop());与外部的交互通过Handler进行;

  • Lopper.prepare() //为当前线程创建Lopper对象,实质上是new一个Looper然后通过当前线程内置的存储类ThreadLoacl保存该Looper,由于每个线程只能有一个Looper,所以通过prepare()创建Looper每次会判断当前线程是否有Looper,有则异常。在这里插入图片描述
  • Looper.loop() //通过死循环来不断取出当前线程Looper的消息队列中的消息,消息队列没有数据了就会挂起,核心代码如下图

在这里插入图片描述

  • Looper.myLooper()//获取当前线程的Looper对象,底层是通过当前线程内置的线程存储类ThreadLoacl.get()来获得,获得的内容在Looper执行prepare()时通过ThreadLoacl.set()传入的Looper对象。

在这里插入图片描述

在这里插入图片描述

  • Looper.myQueue()//获取Looper对应的消息队列
  • Looper.getMainLooper()//获取主线程的Looper对象

拓展 —ThreadLocal

​ ThreadLoacal是Thread中内置的存储类,其本身并不存储数据,而是通过它内置的ThreadLoacaMap来存储数据的。

其主要方法有:

  • set(T t) //设置线程变量
  • get() //获得线程变量,调用前一定要调用set方法否则报空指针异常

在不同线程中执行get方法得到的值是不同的,得到的值是在对应线程set的值

Message

public final class Message implements Parcelable {
    //标识消息
    public int what;
    int flags;
    long when;
    //传递简单数据
      public int arg1;
    public int arg2;
    //传递较复杂数据 对象
    public Object obj;
    Bundle data;
    //处理消息的目标Handler
    Handler target;   
    //消息派发时 执行的Runnable对象
    Runnable callback;  
    //使消息形成链表
    Message next;
    //建立一个消息pool,回收msg,以避免重复创建节约开销
    private static Message sPool;
    private static int sPoolSize = 0;
    private static final int MAX_POOL_SIZE = 10;
  }  

​ Message提供了obtain方法:通过obtain获取,可从MessagePool中获取(MessagePool类似数据库连接池)一个消息,可以节约开销。也通过myhanlder.obtain(),来获取一条target是myhanlder的对象的message。每条消息都有一个target,在某个handler发送消息(send或post)时,最终会将该handler赋值给该message.target,以便于在消息队列取出消息后直调用消息的target去处理消息。

MessagePool

​ 可以将创建的对象用完之后回收,以便再重复利用节约频繁创建释放开销。

public static void loop() {
       while (true) {
  //派发消息
  msg.target.dispatchMessage(msg);

  //消息处理完毕 回收
        msg.recycle();
    }
}     

public void recycle() {
       //回收Message 建立全局的MessagePool
       if (sPoolSize < MAX_POOL_SIZE) {
           next = sPool;
           sPool = this;
           sPoolSize++;
       }
}
  • 20
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值