从源码分析Android中Handler的消息传递机制

本文深入探讨安卓中的Handler机制,解释为何需要Handler,介绍其在消息传递中的作用,并详细解析Handler的工作原理及其相关组件如Message、Looper和MessageQueue的功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 安卓开发人员开始研究安卓源码时,一般都从安卓的Handler消息传递机制开始。在讲安卓消息传递机制前我们要先讲为什么要有Handler

一、什么要有Handler

     在安卓中主线程是不能做耗时和阻塞操作的,我们需要将访问网络和耗时的操作放到子线程中去做,在子线程中获取了数据后经常有更新

    主线程UI的需求,但安卓中子线程不能做更新UI的操作(准确的说是在安卓的审查机制建立后,子线程不能更新UI,只有子线程才能更新UI,

值得注意的是,在安卓审查机制建立前,子线程是可以更新UI的),所以安卓中采用了Handler消息传递机制。可以将Handler看成是线程间

的通讯工具。


二、消息传递机制的大概流程

    在了解流程前我们介绍Handler机制对应的四个对象:

   Handler:发送Message,并且处理自己发送的Message

    Message:消息--数据的载体,放入消息队列(MessageQueue)中,等待 Looper的轮询,之后交给对应的

Handler处理Message中有 target  属性用来标记消息是哪个Handler发送的

Looper:消息轮询对象,在UI线程创建时,就初始化出来,同时创建MessageQueue,并且启动轮询机制,等待消息。一个线程对应一个Looper 

  MessageQueue:消息队列,Handler发送出来的消息,首先放入该队列中,通过Looper的loop方法,取出来交给对应的Handler

<通过Message中的target属性找到>处理。Looper初始化的同时,被创建,一个Looper对应一个MessageQueue (在主线程中创建的) 

一个Looper的可以对应多个Handlaer

![这里写图片描述](https://img-blog.youkuaiyun.com/20161206000848072)
https://img-blog.youkuaiyun.com/20161206092624524
上面例子写了一个简单的主线程中handler的消息传递。
三、从源码分析消息机制的执行流程
   首先我们来了解下Looper的几个方法:

  Looper.prepare() : 通过该方法创建了一个Looper对象,同时Looper对象中会创建了一个消息队列 MessgeQueen,并持有了当前的线程的引用

   Looper.myLooper(): 获取Looper对象(在new Handler的时候会调用mLooper = Looper.myLooper(),如果mLooper==null 会报RuntimeExtion)

  Looper.loop(): 开启一个死循环,有消息就取,没消息就阻塞,在那等,通过messgeQueen.next()不断的取消息,通过message.target.

dispathmesssge()分发消息(即处理消息)。

现在我们来看下主线程中的Handler机制是如何被创建的。

首先我们得明白,安卓在创建主线程时会自动创建一个Looper,系统框架将所有在主线程中的操作封装成消息,然后在loop方法通过

messgeQueen.next不断的取消息(取消息,消息队列中没消息,可能阻塞,进入休眠状态,有新消息来了,通过管道流的机制,快速的

唤醒),通过dispathmesssge分发消息(处理消息,可能有耗时操作,可能ANR),所以耗时操作不能在主线程中做,而要在子线程中

做。

Looper.prepare()的源码

https://img-blog.youkuaiyun.com/20161206101036192

Looper的构造方法

Looper.myLooper()

Looper.loop()很关键,重点看

到此Looper介绍完毕,继续往下看。

创建Handler对象 (前提是当前线程中已经创建了Looper对象) 

  在Handler的构造方法中会执行mLooper =Looper.myLooper()方法获取Looper对象(即对Handler绑定一个Looper对象),如果mLooper==null 会

报RuntimeExtion

获取消息对象

     Messge.obtain  从消息回收队列中取消息,没有就new Message()

     Messge .recycle 将用完的消息放到消息回收队列中 下面代码就将回收的消息,放到回收队列的头部。

发送消息(handler.sendMessge())

    在发消息时会将当前的handler,赋值给了Messge的targte属性,将这个消息加入消息队列MessgeQueen中(如果是延时消息,按时间大小

插入队列) 最终会执行sendMessageAtTime方法。

通过loop()从消息队列中去取消息 并交给messge绑定的handler处理消息

     在loop方法通过messgeQueen.next不断的取消息,通过message.targert.dispathmesssge分发消息,在handler的handMessge方法中执行

具体逻辑

在子线程中也可以处理 (在主线程中发消息,在子线程中处理消息)     

new MyLooperThread().handler2.sendMesssage(mssg);

我们现在可以将多个线程绑定起来用,按一定的顺序执行

现在我们来看子线程弹土司的问题

子线程中可以弹土司,通过加Looper.prepare, 不提倡这么用,因为Looper.loop()是死循环,Acticity退出后,loop()中

的资源得不到释放,造成内存的泄露。

我们来看下Toast的源码:

	
      我看到了Handler,看源码知道,Toast中 有这段代码 final Handler mHandler = new Handler(); new Handler()的提示要有一个Looper,
     那么我们只需在Toast.makeTest().show()前加Looper.prepare(),之后加Looper.loop();就就可以在子线程中弹土司了。

    最后我们重新看下Handler消息机制图:
获取和回收消息对象

消息的入列

感谢大家的阅读,希望对你有所帮助。
参考文章 

深入解析Handler机制 http://www.jianshu.com/p/02962454adf7

	

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值