《Android开发艺术探索》--消息机制

介绍:

在Android中,我们最经常使用的消息传递机制就是Handler+Looper+MessageQueue。这种机制常用于,将耗时任务在另一个线程中运行,而不影响主线程中UI的绘制,只有当任务完成时会通知UI线程进行界面的更新。

Android中只能在主线程中更新UI的原因:
使用这种机制的原因是因为Android中UI线程是非线程安全的,也就是说当多线程进行访问时会出现意想不到的错误,所以就限定只能在主线程,也就是UI线程中更新UI。

简单的说,Handler是用于处理消息的,而Looper则是不断地循环执行,从MessageQueue中取出消息交给Handler处理,MessagesQueue就是一个消息队列。通过这样的一个机制,我们就可以实现在子线程中处理耗时的任务,而通过消息机制发送的消息,在主线程中更新界面,实现了线程之间的通讯。

分析:

ThreadLocal:

ThreadLocal是线程中一个用于保存数据的存储类,通过他可以实现在指定的线程中存储数据,数据存储之后,就只能在该线程中获取到,其他线程无法获取到存储的数据,这就是ThreadLocal的特性。

ThreadLocal工作流程简介:
当调用ThreadLocal的set方法时:

  • ThreadLocal会先从当前线程中取出一个localValues对象(这个对象内部有个Object[]数组,这个object数组就是专门用于保存ThreadLocal的数据的)

    • 若对象不为空,则直接将要保存的值put进数组中,并传入ThreadLocal作为key
    • 若对象为空,则初始化之后将要保存的值put进数组中,并传入ThreadLocal作为key
  • 将数据put到Object[]数组的方式:

    • 首先检查传入的ThreadLocal的reference是否在数组中已经存在,若存在,则进行覆盖,并将值保存在reference所标识的对象的下一个的位置上。
    • 若不存在,则初始化之后将数据保存在reference所标识的对象的下一个的位置上。

当调用ThreadLocal的get方法时:

  • 首先获取到当前线程中的localValues对象数组:
    • 若获取到的localValues为空,则赋予默认值之后返回默认值
    • 若获取到的localValues不为空,则取出其中的Object[]数组,然后找到ThreadLocal的reference的位置,则下一个位置上的数据就是ThreadLocal存储的值。

由于ThreadLocal的存取操作都是对当前线程中的localValues中的Object[]数组进行的,所以就实现了在不同的线程中访问同一个ThreadLocal得到不同的数据副本的功能。

MessageQueue:

消息队列其实就是根据发送消息的时间来组成的一个队列,虽然称之为队列,但其内部其实值用单链表来实现的(更便于插入和删除),提供了enqueueMessage和next两个方法。

  • enqueueMessage用于将消息插入到队列中,也就是实现了单链表的插入操作
  • next方法其实是一个无限的循环,当消息队列的链表中没有消息时就会阻塞在这里,当有消息插入队列中时,它就会将该消息返回,并将其从消息队列的链表上删除。
Looper:

Looper其实就是连接消息队列MessageQueue和Handler的一个中间机制,他不断的从消息队列取出Message,将其交给Handler来处理,只有当MessageQueue返回null时才跳出循环。

创建Looper:
为一个线程创建Looper只需要调用Looper的prepare()方法即可,然后通过looper()方法来开启Looper的循环。对于主线程而言,Android已经在Looper中提供了getMainLooper方法来获取主线程的Looper。

退出Looper:
退出一个Looper有两种方式,一种是直接调用quit()方法,使用该方法会直接退出looper循环;另一种是调用quitSafely(),该方法会将当前消息队列中所有的消息处理完成之后才退出。若是在一个子线程中创建,使用完looper之后没有将其退出,那么looper会始终阻塞在那里,而不是直接销毁,所以应该每次使用完之后就主动的退出looper。

工作流程简介:
looper是不断的获取MessageQueue中的消息的,每当有消息返回时,他会通过msg.target.dispatchMessage(msg)方法将message发回给handler的dispatchMessage()方法,这样handler在其他线程中发送的消息就会在创建handler的线程中进行处理,实现了线程之间的信息状态的通讯。

Handler:

Handler处理消息的步骤分为三步:

  1. 首先检查msg中自带的Callback是否为空,若不为空则将消息交给msg中自带的Callback处理,自带的Callback是一个Runnable对象,也就是在post发送消息时的Runnable参数。

  2. 然后检查handler其内部自带的mCallback是否为空,若不为空则将msg交由mCallback的handleMessage()进行处理

  3. 最后才是handler其自己的handleMessage()方法处理消息。

在平常的使用中我们大部分都是直接派生一个Handler的子类,并重新其中的handleMessage()方法,其实我们也可以考虑通过第二种方式,即通过实现Handler当中的Callback来实现消息的处理。

在了解了Android中的消息处理机制之后我们就可以大体绘制出一个简单的示意图来展示该机制是怎样实现在不同线程之间消息处理的。

描述图片

总结:

其实Android中的消息机制不仅仅只可以用于处理耗时任务和界面更新这种问题,其同样可以用于任何两个线程有通讯需求的情景,同时这种消息处理机制的设计思路也可以为我们提供良好的借鉴。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值