Android Handler源码分析

一.什么是Handelr

  • Android SDK中用来处理异步消息的核心类
  • 子现程可以通过Handler来通知主线程进行更新UI

二.Handler机制的核心类

  • Handler
  • Message
  • Looper
  • MessageQueue
    1.Message:
    在整个消息处理机制中,message又叫task,封装了任务携带的消息和处理该任务的handler。有这么几点需要处理:
    (1)尽管Message有public 的默认构造方法,但是你应该通过Message.obtain()来从消息池中获得空消息对象,以节省资源
    (2) message 如果只需要携带简单的int信息,请优先使用arg1和arg2来传递信息,这比用bundler更节省内存。
image.png

三.源码分析

1.handler在哪个地方使用在哪个地方点进去看
image.png
2.进入到sendMessage()
image.png
3.再进入到sendMessageDelayed()
image.png
4.进入sendMessageAtTime()
image.png
image.png

会看到调用的各种发送消息的方法,最终都会走到这个方法。

5.msg 里面有个成员变量拿到了handler的引用,最后一句代码进入消息队列
image.png
6.点进入MessageQueue中看
image.png

消息入队方法enqueueMessage(),一个线程就只有一个消息队列 ,这里的MessageQueue不是一个链表结构,其实它是一个链式结构,就是单链。


image.png

这里大致,就是根据延时时间把要插入的message插入响应的位置,如果延时时间为0,新消息就会插入到队头,如果延时时间不为0 就会和队列里的其他消息对比插入到应用位置。


image.png

既然有入队,对应就有出队,出队是在messageQuenue方法中的next()方法,就是把message消息从队列里面取出返还给looper

7.点进looper看
image.png

looper 中拿出消息,有可能会堵塞,当我们队里里面没有消息,或者message的延时时间没到,他就会进行堵塞。


image.png

上面说过msg 的target保存的是handler 的引用,所以这句话调用的是handler 的dispatchMessage()方法,然后我们回到handler 看看这个方法。

8.回到Handler类
image.png

然后看到数据的方法在dispatchmessage中最后调用了handlerMessage()


image.png

这个handelMessage是子类必须实现的方法,也就是我们创建handler 必须实现的方法。

9.回到我们创建的Handler子类
image.png

其实如果我们的message不拿handler 这个句柄的话也可以实现,我们也可以再创建一个类,把message传给这个类,像实现handlemessage方法一样,但是这样我们使用者就要学习更多的handelr 知识,不但要了解handler还要会使用新类和message,这就导致我们学习成本更高了,所以这也是一个设计思想,方便使用者更简单,更方便的调用,直接把message返回给handler引用,传入到handlerMessage方法,让子类去实现这个方法,

下面我们来具体的梳理下流程

image.png

1.创建Handler子类通过调用sendMessage() 发送消息
2.Handelr 最终调用messageQuene的enqueueMessage()将消息传入到消息队列中
3.Looper中的调用MessageQueue的next()方法将取出消息。
4.Looper中通过Message的成员变量target拿到Handler的引用,继而回调到Handler的 handelMessage()方法
5.消息回到我们创建的子类实现的HandelMessage()方法

四.但是现在有几个疑问

  • looper 谁调用的
  • sendMessage是在子线程中发送的消息,为什么最后handleMessage 又回到了主线程
  • 为什么messagequen 只有一个
1.Looper中创建MessageQueue ,主线程中ActivityThread调用Looper。
image.png

我们看我们new Handelr() 里面调用了this(null,false),false 又是什么


image.png

代表callback 和async ,callback又是什么,我们回到dispatchMessage方法看


image.png

我们创建时 callback为空就会进入else方法,else里面又为空,就会走handlerMessage方法
image.png

再看Handler构造函数中调用Looper.myLooper(),


image.png

再点进ThreadLocal是什么东西


image.png

ThreadLocal是做线程间数据隔离用的,就类似我们多线程操作共享数据,需要有同步锁机制,我们就记住,ThreadLocal对象最后返回的是当前线程的Looper对象
image.png

最后回到handler 中看如果mLooper 为空就会抛出异常,因为还没有调用Looper.prepar(),下面 mQuene=mLooper.mQueue,消息队列实际是从Looper中返回的,他是在Looper里,再来看Looper.prepar()是干什么


image.png

点进prepare()
image.png

prepare() 如果不为空,抛出异常,提示一个线程只能有一个Looper ,为空则创建一个Looper ,ThreadLocal 操作和map很像通过set去放,通过get去拉,点击newLooper看
image.png

创建了一个MessageQuene

在回到Looper中看,刚才prepare传的是true,还有什么地方传false,原来prepareMainLooper().传的是false ,那prepareMainLooper是谁调用的


image.png
image.png

ActivityThread 类里面调用了这个方法,那为什么主线程会传prepare()会传false,因为主线程的looper 是不允许退出的 ,因为你退出了再发handler 消息谁来处理呢

image.png

再来看looper的构造函数为私有,也就是一个线程只有一个looper,每个线程也就有一个对应的looper ,一个looper 又只有一个meesageQuene 也就是一个线程里只有个messageQuen 一个looper

2.Handler 消息驱动

再来考虑一个问题,为什么looper 轮训器一直轮训messagequne缺没有造成阻塞

image.png

看for循环中有消息就立即处理,因此handler 是通过消息驱动的,没有阻塞说明有消息要处理,阻塞是因为没有消息,或消息的延时时间未到

3.Handler 线程切换由于线程间内存共享

为什么会切换线程:一个app里面的内存,就是我们进程,进程与进程之前的内存是不共享的,但是线程与线程之间的内存是共享的,在子线程能拿到主线程创建的handler,而主线程的looper 对象是在ActivityThread中main方法创建的 那looper.looper()也在主线程中,那looper 中的dispatchMessage().也是在主线程 ,也就是创建和接受在主线程中 只有发送和入队是在子线程中


image.png

看完handler源码 很明显的看到handler 的设计模式就是一个生产者与消费者的模式

总结:

1.一个线程中只能有一个looper 所以,一个线程也就只能有一个MessageQueue,因为 Looper在构造方法中创建MessageQueue 队列 。

2.主线程的Looper 调用默认在ActivityThread中已经调用开启。

3.Handler是消息驱动的所以Looper轮训器一直轮询消息并没有阻塞主线程。

4.Handler实现线程切换的原因是线程间内存是共享的。

5.MessageQueue中有两个主要的方法,一个是消息入队方法enqueueMessage() 一个是消息出队方法 next()

(1)enqueueMessage():消息入队,插入消息的时候对消息进行排序

(2)next():消息出队,next 方法在looper中调用,消息出队过程中会出现队列阻塞,阻塞原因就是队头的消息延迟时间未到,或者现在消息队列没有消息

https://study.163.com/course/courseLearn.htm?courseId=1209146813#/learn/live?lessonId=1278714699&courseId=1209146813

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

推荐阅读更多精彩内容