Handler机制

handler通信实现的方案实际上是一种内存共享的方案

为什么线程间通信不会干扰,加了锁,内存管理设计的很完善

  • 通过loop.loop启动loop.就开始了一个死循环,循环去队列中进行取值
    loop取到一个为null的message,则会退出

  • handler发送消息,不管send post到最后,都会到sentMessageAtTime,在这个方法里面,调用到enqeueMessage.在这个方法内,接着走到了queue.enqeueMessage()这里会把时间穿进去
    这个方法内,会把消息插入队列中(排序算法:插入排序)。

  • messageQueue next方法,会返回message消息,相当于取消息的方法
    这个next的方法调用,会在looper里。在loop方法内,有个for死循环,在这里会调用queue.next方法。然后取出message后,在这里方法里,接着调用到了msg.target.diaptachMessage方法。
    在这个方法内,会走到handleMessage

  • 消息队列,messageQueue, 是一个优先级队列,由单链表实现的。 因为next取值的时候,默认取第一个,所以,他相当于先进先出的数据结构,也就是队列。

Loop

  • 核心有三个 构造函数 loop ThreadLocal
  • Loop类里有个私有的构造函数,所以其初始化有prepare方法完成
    image.png
  • 所以说到loop的初始化,就必须说到ThreadLocal---他是一个线程上下文的存储变量.ThreadLocal本身是不存储数据的,他存储数据主要是因为内部的一个类ThreadLocalMap。


    image.png

    他存储数据是通过线程获取ThreadLocalMap。每一个线程都有一个ThreadLocalMap成员变量threadLocals
    一个线程里只有一个loop,就是根据threadLocal保证的

ThreadLocal

  • ThreadLocal 里有一个静态内部类ThreadLocalMap。实际存储数据的东西是ThreadLocalMap,他里面维护一数组,并对ThreadLocal求模获得下标进行存储。
  • 而每个looper里有一个MessageQueue,所以,MessageQueue是跟looper绑定 ,所以也就是每个线程只有一个MessageQueue,并且其声明是final

而且 static final ThreadLocal sThreadLocal = new ThreadLocal();因为是static final,所以这个变量在整个Android唯一

handler内存泄漏的原因

是因为生命周期的问题,所以并不仅仅是内部类持有外部类引用,而是因为他们声明周期不同。之所以生命周期不同,是因为在handler sendmessage的时候,执行到handler的enqueueMessage的msg.target赋值为了当前handler,这个队列的生命存在周期可能很长,所以导致handler释放不了,然后handler拿着外部的引用,导致了外部也无法释放

子线程消息队列无消息后应该怎么做

  • 调用looper.quit方法,此时会处理掉什么消息,并唤醒消息队列的循环(无消息的时候会让他睡眠),然后因为给一个判断的变量mQuitting赋值为true了,所以在循环操作里,监测到这个true
   // Process the quit message now that all pending messages have been handled.
                if (mQuitting) {
                    dispose();
                    return null;
                }

在此处messageQueue的next方法返回为null,


        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

也就是Looper的loop方法里msg为null,然后就return了。

  • 所以quit方法做了什么事?---唤醒睡眠的线程(因消息为null睡眠了)--MessageQueue里mQuitAllowed设置为true ---导致next返回null--导致loop方法里得到null后return 退出

为什么多个线程都可以往消息队列中放消息,是怎么保证线程安全的

  • 因为加锁了
   boolean enqueueMessage(Message msg, long when) {
          ...
      synchronized (this) {
          .....
      }
        .....
   }

注意此处锁的是this,所以也就是对同一个这个对象的访问是有锁的,但是对不同对象是没事的,因为this不同
为什么取消息的时候也有synchronized (this)------因为从这个队列中取的时候,有可能有其他消息要进来,而且可能会插队(比如同步屏障或者延时消息的插队)

message的创建问题---大量new出来对象后为何不会内存抖动(full gc虽然会处理这些碎片,但是无法控制)和oom,其中涉及到了享元设计模式(内存复用,不是指的数据复用),在loop取出消息后,并没有直接将这个对象释放,而是msg.recycleUnchecked();

你可能感兴趣的:(Handler机制)