Handler消息详解

在android开发中,通常会在子线程中进行一些操作,当操作完毕后会通过handler发送一些数据给主线程,通知主线程做相应的操作。子线程通过handler向主线程发消息的模式,其实就构成了 生产者-消费者模型。生产者-消费者模型:生产者和消费者在同一时间段内共用同一个存储空间,生产者往存储空间中添加数据,消费者从存储空间中取走数据。
handler.sendMessage发送消息到消息队列MessageQueue,然后looper调用自己的loop()函数带动MessageQueue从而轮询messageQueue里面的每个Message,当Message达到了可以执行的时间开始执行,执行后就会调用message绑定的Handler来处理消息。
无论何种方法发送Message,最终都会走到Handler的enqueueMessage方法最终生成MessageQueue,用存和取解决同时发生时,速率不一致问题;这是生产者和消费者模式,演进为多线程通信。大量消息过来时容易造成阻塞,通过队列的方式解决。一个线程可以有多个handler,一个线程只有一个loop,必须一个线程对应一个队列。可以通过Thread,currentThread()方法获取到当前线程。在线程Thread里有找到ThreadLocalMap。线程实际上就是一个Thread对象。通过ThreadLocal找到Thread对应的ThreadMapThreadMap实际上就是一个hashMap存放着key和Value。key就是this就是当前ThreadLocal,value就是looper。loop的生命周期,就是当前线程的生命周期长度。怎样保证一个线程里只有一个looper?利用sThreadLocal将looper对象存到了Thread对象map中;在存的时候先去找,如果之前有存的话则会去抛异常。

常见问题:
1,Handler为何会造成内存泄漏?以及怎样解决?
造成handler内存泄漏的原因:

一个线程,只有一个looper,但是却可以有无数个handler。我们将looper中的传递的消息队列meassageQueue拿到,这时候需要去遍历meassageQueue拿到每一个message去调用handleMessage方法。因为handleMessage是创建的handler对象的方法,一个线程可以有无数个handler但是却只能有一个looper。因此并不能确定调用哪一个handler里的handleMessage方法。因此并不能完美的做到一一对应的关系,所以无解。
最终妥协产物是让每个Message持有handler。实例化Message的时候将handler传进来,因此才能调用每个msg对应的handleMessage,这样就造成handler的这个内部类是持有外部类的。
持有链:
线程–>looper–>MessageQueue持有–>msg持有—>myHandler持有MyActivity
本质是长生命周期对象持有短生命周期的对象。

解决方法:

将handler内部类前加static变成静态内部类,这样可以避免内部类隐式持有外部类的引用。
持有外部类的额弱引用,
在onDestory中用handler的removeCallbacksAndMessage方法来移除.

2,epoll机制什么意思?

epoll内会维护一个B+树也就是红黑树。
在ActivityThread的main函数中,去调用looper.prepareMainLooper就是在调用prepare向树里去注册它接下来会去实例化这个looper然后再去实例化MessageQueueMessageQueue就会去调用nativeInitnativeInit就会往这个红黑树里面去添加,这样的结构每个app都会给他分配一个句柄这个句柄就是红黑树。这时有个事件过来了,它会标记是哪个app去接收,比方这个事件标记7,那么它就会在这个epoll里面找到这个7然后再调用looper.loop遍历的时候看起首先拿到MessageQueue这个单向链表单向链表不能阻塞,在for循环, 调用queue.next,next内也在for循环,是个死循环,在调用nativePollOnce实现这种阻塞式队列功能,用时间顺序实现阻塞首先会把message里的时间拿出来,拿出来不断去遍历。如果现在时间now大于message里的when时间,它马上就会把消息拿出来,小于消息时间就会走nativePollOnce跑出来,此时调用pollOnce,实际上是调用当前对象的pollOnce接下来就是调用looper.pollOnce又调用了pollInner(pollInner有很重要得几点,一个是epoll_wait,它属于linux函数,是等待一个文件得IO每个app在最开始都会去注册文件,注册文件调用得是epoll_creat,会去红黑树里面去注册)底层通过epoll_ctl发消息传递事件,然后epoll_wait会去等待,这里就会产生阻塞,有一个等待队列,一个个去响应红黑树解决的是查询问题,epoll可以解决百万级别的事件。

  • 8
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值