android消息机制

Android消息机制主要指Handler的运行机制,Handler只是Android消息机制的上层接口,依赖于底层MessageQueue和Looper。

MessageQueue:消息队列,内部存储了一组消息,以队列的形式对外提供插入和删除操作。虽然叫消息队列,但是它的内部存储结构并不是真正的队列,而是采用单链表的数据结构来存储消息列表的。

Looper:循环器,由于MessageQueue只是一个消息的存储单元,并不能去处理消息,所以就有了Looper的概念,Looper以无限循环的形式去查是否有新消息,如果有新消息就处理,否则一直等待。

Looper中还有一个特别的概念:ThreadLocal,它并不是线程,他的作用是可以再每个线程中存储数据,Handler在创建的时候会采用当前线程的Looper来构造消息循环系统,而ThradLocal可以再不同的线程中互不干扰的存储并提供数据,通过ThreadLocal,Handler就可以轻松获得每个线程的Looper。线程是没有Looper的,要使用Handler就必须为线程创建Looper。

Handler的主要作用是将一个任务切换到某个指定的线程中去执行,之所以提供这个功能是因为:UI线程不能进行耗时操作,但是UI更新却只能在UI线程中进行,所以才有了切换线程的概念和Handler。ViewRootImpl中的checkThread方法回去检测当前访问UI的线程是不是UI线程。

为什么不能再子线程中访问UI:Android的UI控件并不是线程安全的,如果在多线程中并发访问可能会导致UI控件处于不可控的状态。

为什么不加锁机制呢?锁机制会让访问变得复杂,其次会降低UI的访问速率,因为锁机制会阻塞某些线程的执行,因此采用单线程模型来处理UI操作。

Handler通过send方法时通过调用MessageQueue的enqueueMessage方法将这个消息加入到消息队列中,然后Looper发现有新消息到来,就会处理该消息,然后消息中的Runnable或者Handler的handlerMessage方法会被调用。

注意:Looper运行在创建Handler的线程中,这样Handler中的业务逻辑就被切换到创建Handler所在的线程中去执行了。

ThreadLocal是一个线程内部的数据存储类,可以在指定的线程中存储数据,数据存储以后,只能在指定的线程中可以获取,对于其他线程来说则无法获取。

ThreadLocal的使用场景:当某些数据以线程为作用域并且不同线程具有不同的数据副本的时候。很显然Looper的作用域就是Handler所在的线程,

同一个ThreadLocal在不同的线程中进行数据存储时,ThreadLcoal内部会从当前的线程中获取到一个Values,然后以键值对的方法将其存储,所以一个ThreadLocal内部针对不同的线程会有不同的数据副本。其实更准确的说就是:ThreadLocal内部会对每一个线程维护一个Values对象,然后每一个线程对应的数据副本都存储在该线程的Values中。

MessageQueue主要包含两个操作:插入和读取,读取操作本身伴随着删除操作。插入和读取对应的方法分别为:enqueueMesssage和next,其中enq
ueueMessage的作用往往是往消息队列中插入一条消息。next的作用是从消息队列中取出一条消息并将其从消息队列中移除。因为单链表在插入和删除上的优势,所以MessageQueue内部使用单链表的结构实现。next是一个无限循环的方法,如果消息队列中没有消息,next方法就会一直阻塞在这里,如果有新消息到来,next就会返回这条消息并将其从单链表中删除。

在线程中可以通过Looper.prepare方法为当前线程创建一个Looper,然后在该线程中使用Handler,然后通过Loop.loop开启消息循环。对应的prepareMainLooper则会给主线程创建一个Looper,ActivityThrad中就是使用这个方法构建Looper的。而由于主线程的特殊性,系统又提供了getMainLooper方法在任意地方均可以获取到主线程的Looper。在子线程中,如果手动为其创建了Looper,那么所有的事情做完之后,应该调用quit方法来终止消息循环,否则这个子线程就会一直处于等待的状态,而如果退出Looper以后,这个线程也会立刻终止。

Looper的loop方法是一个死循环只有当MessageQueue的next方法返回null的时候,才会跳出循环。当Looper的quit方法被调用以后,他就会调用MessageQueue的方法通知消息队列退出 ,如果当前消息队列被标记为退出状态,那么他的next方法就会返回null,Looper的loop方法也就跳出了循环,否则会一直循环。loop方法会调用MessageQueue的next方法来获取最新消息,而next是一个阻塞操作,没有消息时会一直阻塞在那里,这也会导致loop方法一直阻塞。如果MessageQueue的next方法反回了新消息,Looper就会处理新消息,调用Message对应的Handler的dispatchMessage方法,这样Handler发送的消息最终就又交给了他自己的diapatchMessage方法,

Handler发送消息主要是通过post和send,post最终也是通过send去发送的。Handler发送消息就是像消息队列中插入一条消息,然后looper轮询的时候调用MessageQueue的next方法,如果有消息就会调用该Message对应Handler的diapatchMessage方法,在dispatchMessage内部会通过message的callback方法是否为空,去执行post传过来Runnable的run方法还是CallBack对象的handleMessage方法。

主线程的消息循环机制:Android中的主线程就是ActivityThread,主线程的入口方法为main,在main方法中通过Looper.prepareMainLooper方法来创建主线程的Looper以及MessageQueue,并通过Looper.loop来开启消息循环。主线程的消息循环开启了以后,ActivityThread还创建了一个Handler来和消息队列交互,这个Handler就是ActivityThread的一个内部类H继承与Handler,该类内部定义了一组消息类型,主要包含了四大组件的启动和停止过程。ActivityThread通过ApplicationThread和AMS进行进程间通信,AMS以进程间通信的方式完成ActivityThread的请求后回调ApplicaitonThread中的Binder方法,然后 ApplicationThread会像H发送消息,H接收到消息后会将ApplicationThread中的逻辑切换到ActivityThread去执行,即切换到主线程中去执行,这个过程就是主线程的消息循环模型。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值