Handler消息处理机制总结

一、从构造函数开始

Handler构造函数

可以看到,Handler的构造函数里,关联了Looper(通过Looper.myLooper()方式取得)、Queue(MessageQueue,从Looper中取得)、Callback()、async.

接下来,看一下 Looper.myLooper():

Looper.myLooper()

myLooper()取得的Looper是存储在ThreadLocal中的。通过looper.prepare()初始化并存储:

Looper.prepare()

通过方法,可以看到,prepare()函数只能被调用一次,不然会throw Exception。这样可以保证,一个ThreadLocal中只存在一个Looper。

再看Looper的构造函数:

new Looper()

在looper的构造方法里,主要做了两件事:

1、创建一个looper管理的消息队messageQueue;

2、获得当前的线程;

到这里,Handler的构造函数,基本流程跑完。总结一下,new 一个handler的时候,会得到一个绑定在ThreadLocal中的Looper实例、一个与Looper绑定的MessageQueue实例,这三个实例对象互相绑定,从而进行信息交流。


二、信息发送流程。

handler通过sendMessage()、sendMessageDelayed()、sendMessageAtTime()等方法发送信息,最终这些方法都会走入同一个方法:enqueueMessage()

handler.enqueueMessage()

在enqueueMessage()方法中,先是将本handler对象赋值msg.target.之后执行了messageQueue的消息队列插入消息操作MessageQueue.enqueueMessage():

MessageQueue.enqueueMessage()

此函数执行的是单链表的插入操作,从此也可以看出。MessageQueue实际上是由单链表实现的。


三、消息处理流程。

将Message插入MessageQueue之后,我们知道。与MessageQueue绑定的Looper会调用 loop()方法一直循环遍历MessageQueue:

Looper.loop()

清晰明了,获取当前looper和与其对应的MessageQueue。通过一个for(;;)死循环,从MessageQueue中遍历获取Message。这边注意,messageQueue.next()方法中如果没有Message,会在next()方法中block住,直到有Message被enQueue入MessageQueue队列中,next()方法继续执行,loop()也可以瞬间得到Message。而只有在looper调用quit()或quitSafely()方法,messageQueue的next()方法才会返回null(此时MessageQueue同样调用了quit()方法),此时loop的无限循环也将结束。

looper.quit()和looper.quitSafely()的区别是:quit()直接退出Looper,quitSafely()只是设置一个退出标志,等消息队列中的消息处理完毕,就会退出Looper,这时候Handler的send方法返回false。如果在子线程中手动创建了Looper,要记得退出Looper,不然这个线程会一直处于等待转态,如果退出了,这个线程也会被终止。

接下来,我们来看一下 MessageQueue的next()方法:

MessageQueue.next() part1
MessageQueue.next() part2

就像我们之前说的那样,如果单向链表中有Message,便取出这个Message return出去,如果链表中已经没有Message,便通过Binder.flushPendingCommands()  block当前操作。


回到Looper.loop()中,当looper从MessageQueue中得到Message之后,便会调用msg.target.dispatchMessage(msg)去处理Message。之前我们提到过,在Handler发送消息的enqueueMessage()方法中,已经将当前Handler赋值给了msg.target.此时,便是将发送message的handler变量取出,调用其dispatchMessage(msg)方法处理Message。

Handler.dispatchMessage(msg)

Handler的消息处理过程如下:

首先先检查Message的callback是否为空,不为空就通过handleCallback来处理,Message的callback是一个Runnable对象,实际上就是Handler的post方法所传递的Runnable参数

其次检查mCallback是否为null,不为null就调用mCallback的handleMessage方法来处理,Callback是个接口,定义如下:

public interface Callback {

    public boolean handleMessage(Message msg);    

}

通过Callback可以采用如下方法创建Handler handler = new Handler(callable)。在日常开发中,创建Handler最常见的方式是派生一个Handler的子类并且重写它的handleMessage方法,另外一种是传入一个Callback,并实现callback的handleMessage方法。

最后调用Handler的handleMessage方法来处理消息。

处理过程的流程图:


Message处理流程图


四、Handler使用注意事项

1、创建massage对象时,推荐使用obtain()方法获取,因为Message内部会维护一个Message池用于Message的复用,这样就可以避免 重新new message而冲内心分配内存,减少new 对象产生的资源的消耗。

2、handler 的handleMessage方法内部如果有调用外部activity或者fragment的对象,一定要用弱饮用,handler最好定义成static的,这样可以避免内存泄漏;为什么呢?因为一但handler发送了消息。而handler内部有对外部变量的引用,此时handler已经进入了looper的messageQueue里面。此时activity或者fragment退出了可是区域,但是handler内部持有其引用且为强引用时,其就不会立即销毁,产生延迟销毁的情况。

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

推荐阅读更多精彩内容