Android-消息机制

整体机制

一共有四个角色,Handler消息处理者、Looper消息循环、MessageQueue消息队列、Message消息。当handler调用post或者sendMessage时,最后都会调用内部的sendMessageDelayed方法,再通过enqueueMessage方法,设置了msg.target并将消息加入MessageQueue,在MessageQueue中调用了nativeWake唤醒了next方法中的nativePollOnce。而Looper的loop方法此时因为MessageQueue的next方法被阻塞着,直到next方法返回这条msg,Looper的loop调用了msg.target.diapatchMessage。到达了Handler 的事件分发,进行消息处理。

Thread、Looper、Looper.myLooper,Looper和线程的关系是如何建立关联的,ThreadLocal的实现在其中起了什么作用

从线程中取出myLooper的过程(字节)
Looper.java
有一个static final变量sThreadLocal = new ThreadLocal<Looper>();
Looper.myLooper()是调用了sThreadLocal.get()
ThreadLocal.java
ThreadLocal.get()中获取currentThread,
拿到Thread中的变量ThreadLocalMap,
Thread.java
变量ThreadLocal.ThreadLocalMap,数据被存在了该类中的Entry[] table
ThreadLocal.java
map.getEntry(this)->用和HashMap一样的方式计算下标(hashCode&(table.len-1))
两个变量合流,拿到了ThreadLocalMap.Entry,(Entry是ThreadLocal弱引用和value的键值对组合)
entry.value就是我们需要的Looper

Handler中的delay是如何实现的(字节)

在MessageQueue.next()里,如果头部的这个Message是有延迟而且延迟时间没到的(now < msg.when),会计算一下时间(保存为变量nextPollTimeoutMillis),然后在循环开始的时候判断如果这个Message有延迟,就调用nativePollOnce(ptr, nextPollTimeoutMillis);进行阻塞。nativePollOnce()的作用类似与object.wait(),只不过是使用了Native的方法对这个线程精确时间的唤醒。

postDelay()一个10秒钟的Runnable A、消息进队,MessageQueue调用nativePollOnce()阻塞,Looper阻塞;
紧接着post()一个Runnable B、消息进队,判断现在A时间还没到、正在阻塞,把B插入消息队列的头部(A的前面),然后调用nativeWake()方法唤醒线程;
MessageQueue.next()方法被唤醒后,重新开始读取消息链表,第一个消息B无延时,直接返回给Looper;
Looper处理完这个消息再次调用next()方法,MessageQueue继续读取消息链表,第二个消息A还没到时间,计算一下剩余时间(假如还剩9秒)继续调用nativePollOnce()阻塞;
直到阻塞时间到或者下一次有Message进队;
这样,基本上就能保证Handler.postDelayed()发布的消息能在相对精确的时间被传递给Looper进行处理而又不会阻塞队列了。

Handler如果没有消息处理是阻塞的还是非阻塞的(字节)

https://blog.csdn.net/u010126792/article/details/85091348
阻塞的。Looper.loop阻塞在MessageQueue的next方法中,有一个nativePollOnce的native方法,而在MessageQueue的enqueueMessage方法的最后nativeWake方法可以唤醒阻塞,使用了epoll机制

在next()方法内部,如果有阻塞(没有消息了或者只有Delay的消息),会把mBlocked这个变量标记为true,在下一个Message进队时会判断这个message的位置,如果在队首并且时间满足条件,会调用nativeWake()方法唤醒线程!

Handler的post和postDelay的区别(字节)

都是用sendMessageDelayed实现,postDelay设置了delay数值,而post的delay数值为0,接着调用sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis)

一个线程可以有几个Looper可以对应几个Handler,同一线程,HandlerA能向HandlerB发送消息吗(字节)

一个线程只能又一个Looper,可以有多个Handler,不能互相发送消息,因为dispatchMessage中通过msg.target记录了发送这个Message的Handler

Looper如何在子线程中创建(字节)

直接使用HandlerThread
Looper.prepare();//Looper初始化
mHandler = new Handler(Looper.myLooper());
Looper.loop();//死循环

线程中的Looper创建

在主线程ActivityThread创建时进行了主线程Looper的初始化,handler依赖于Looper,通过构造函数建立联系,而MessageQueue的实例在Looper中,新建的线程需要我们自己调用Looper.prepare();通过构造函数传入handler,然后用Looper.loop();开启消息机制。Android规定访问UI只能在主线程中进行,否则抛出异常(UI控件不是线程安全的,加锁使逻辑复杂,访问效率降低),通过ViewRootImpl对UI操作做了验证,由checkThread方法完成。

handler.post(Runnable) runnable是如何执行的,handler分发的顺序如何

自己新建了Message并且把Runnable赋值给了Message的callback,在loop中会调用msg.target.dispatchMsg()以一定顺序执行第一顺序就是Message中的callback

  1. Message中的callback
  2. 构造函数中传入的callback
  3. 由其子类重写的handleMessage
    handler的Callback和handlemessage都存在,但callback返回true handleMessage还会执行么
    不执行,mCallback.handleMessage如果返回true,会return,即使handleMessage被重写了,也轮不到执行了

IdleHandler

https://blog.csdn.net/jdsjlzx/article/details/110532500
Q:IdleHandler 有什么用?
IdleHandler 是 Handler 提供的一种在消息队列空闲时,执行任务的时机;
当 MessageQueue 当前没有立即需要处理的消息时,会执行 IdleHandler;
Q:MessageQueue 提供了 add/remove IdleHandler 的方法,是否需要成对使用?
不是必须;
IdleHandler.queueIdle() 的返回值,可以移除加入 MessageQueue 的 IdleHandler;
Q:当 mIdleHanders 一直不为空时,为什么不会进入死循环?
只有在 pendingIdleHandlerCount 为 -1 时,才会尝试执行 mIdleHander;
pendingIdlehanderCount 在 next() 中初始时为 -1,执行一遍后被置为 0,所以不会重复执行;
Q:是否可以将一些不重要的启动服务,搬移到 IdleHandler 中去处理?
不建议;
IdleHandler 的处理时机不可控,如果 MessageQueue 一直有待处理的消息,那么 IdleHander 的执行时机会很靠后;
Q:IdleHandler 的 queueIdle() 运行在那个线程?
陷进问题,queueIdle() 运行的线程,只和当前 MessageQueue 的 Looper 所在的线程有关;
子线程一样可以构造 Looper,并添加 IdleHandler;

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,783评论 5 472
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,396评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,834评论 0 333
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,036评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,035评论 5 362
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,242评论 1 278
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,727评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,376评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,508评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,415评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,463评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,140评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,734评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,809评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,028评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,521评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,119评论 2 341

推荐阅读更多精彩内容