Tip | Android的消息机制

底层要点简述

详细的,可以看一下这篇博客给ThreadLocal的关键分析Android(Java) | 如何使程序实现线程安全(拓展分析:ThreadLocal、重排序、volatile/final)

  • 首先,底层实现了一个线程本地存储,叫ThreadLocal区域,
    一个主线程以及它对应的所有子线程,共享同一个 ThreadLocal对象,
    这个ThreadLocal对象中可以说逻辑上维护着一个内存空间
    这个内存空间为不同的线程一 一 对应地维护一套数据副本【t.thread】
    每一套数据副本对应着一个线程
    (有多少线程共享这个ThreadLocal对象,ThreadLocal对象就准备多少套数据副本createMap(t, value)】),
    每一套数据副本在这里可以具体化为一个Object数组

不同线程访问同一个ThreadLocal的get方法,
比如对应线程的Looper,
ThreadLocal的索引值(key)就是ThreadLocal为每个线程创建的独立的threadLocals实例(ThreadLocal<Looper>对应)
value就是不同线程自己的Looper对象;

  • 而主线程及其所有子线程都可以开辟自己的Looper
    每一个Looper都要绑定在一个Handler上,(如下方图1图2)
    然后这些个每个单独的Looper
    都是Looper对应线程共享的ThreadLocal中某一个数据副本中的一个项的value
    这个项有keyvalue两部分,
    value是刚说的每一个线程对应的Looper
    然后这个唯一的静态的Looper对象了关联着一个MessageQueue


整个消息机制的工作流程常规表述

  • 首先在需要传递消息的地方,我们构造一个Message(消息)对象,
    此时Message中会有自己的一个ID
    然后我们把需要传递的数据设置在这个Message里面,
    借助HandlersendMessage() 方法将Message传递到MessageQueue中,
    此时MessageQueue通过调用MessageQueue.enqueueMessage()MessageQueue自身中添加这条发送过来的Message

  • MessageQueue(消息队列)中存放着诸多相关联的Handler发送过来的Message
    其内部通过单链表的数据结构来维护消息列表,
    等待Looper的抽取。

  • Looper(消息泵)通过Looper.loop()不断轮询MessageQueue
    调用MessageQueue.next(),从MessageQueue中抽取队头的Message
    接着调用这个Message对应的HandlerdispatchMessage()
    将该Message传递分发给对应的Handler

  • 目标Handler收到Message后调用handlerMessage()处理这个消息。

图0

附图

图1

机制中相关元素的数量关系

Thread(线程):负责调度整个消息循环,即消息循环的执行场所。
存在关系:

  • 每个Thread(包括主线程、子线程)都可有且只能有一个Looper,可以有多个Handler;
  • Looper有一个MessageQueue,可以处理来自多个(绑定同一个Looper)Handler的Message;
  • MessageQueue有一组待处理的Message,这些Message可来自不同的Handler;
  • Message中记录了负责发送和处理消息的Handler;
    一个Message对应一个Handler,
    一个Handler可以发送多个Message;
  • Handler绑定Looper(默认绑定主线程)和MessageQueue;
图2

参考资料:

实用要点总结

  • 主线程创建时,会自动创建一个默认的Looper对象,而Looper对象的建立将自动创建一个MessageQueue。其他非主线程,不会自动创建Looper,需要的时候通过prepar函数实现。
  • 每一个MessageQueue都不能脱离Looper而存在,
    Looper对象的创建是通过prepare函数来实现的。
  • 同时每一个Looper对象和一个线程关联。
    ·通过调用Looper.myLooper()可以获得当前线程的Looper对象,创建一个Looper对象时,会同时创建一个messagequeue对象。
  • 除了主线程有默认的Looper,
    其他子线程默认是没有MessageQueue对象的,默认不能接受Message。
  • 如需要接受,子线程需自己定义 一个Looper对象(通过prepare函数),这样该线程就有了自己的Looper对象和MessageQueue数据结构了。
    Looper从MessageQueue中取出Message然后,交由Handler的handleMessage进行处理。处理完成后,调用Message.recycle()将其放入Message Pool中。
  • 以上理论详见 —— Android之Message、handler学习
  • 相关博客 ——通信之线程间通信(上)-handler

public class HandlerThreadActivity extends Activity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_handler);
        TextView textView = (TextView) findViewById(R.id.tv);
        textView.setText("HandlerThreadActivity.class");
 
        HandlerThread handlerThread = new HandlerThread("HandlerThread");
        handlerThread.start();
 
        Handler mHandler = new Handler(handlerThread.getLooper()){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                Log.d("HandlerThreadActivity.class","uiThread2------"+Thread.currentThread());//子线程
            }
        };
 
        Log.d("HandlerThreadActivity.class","uiThread1------"+Thread.currentThread());//主线程
        mHandler.sendEmptyMessage(1);
    }
}

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

推荐阅读更多精彩内容