Android中的消息机制(Handler)



Android消息机制,这里主要讲一下Handler机制。
首先需要知道的是在Android中,子线程是无法访问UI的,如果需要在子线程更新UI,必须切换到主线程,否则程序将会报错。这个验证工作是由ViewRootImpl的checkThread方法来完成。

主要原因有两点:
(1)UI控件不是线程安全,子线程访问可能会导致UI控件处于不可预期的状态
(2)如果给UI控件加上锁,首先会降低UI访问的相率,因为锁会阻塞某些线程的执行;其次会使得UI访问的逻辑变得复杂。

Handler机制的主要流程图

  Handler机制主要是Handler、Looper、MessageQueue三个类。这里简要叙述一下流程。在线程中使用Handler的post或者send的一系列方法都是向MessageQueue中插入了一条消息,MessageQueue的内部实现其实是一个单链表,Looper会循环地从MessageQueue中获取消息,然后在Looper所在的线程调用Handler.handleMessage方法或者mCallBack.handleMessage来处理消息。这就是大致的整个流程,下面是具体的几个类的分析。
  需要值得注意的是,主线程是不需要创建Looper和MessageQueue,系统会自动创建。子线程需要自己创建并开启循环。

2.对ThreadLocal的分析
ThreadLocal是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,获取也只能在指定线程中获取。
Public class ThreadLocal<T>,根据定义ThreadLocal是一个泛型类,其主要的方法是get和set方法。
(1)


set方法中,首先通过values方法获取当前线程中的ThreadLocal数据,然后通过values的put方法将其存储在一个table数组中,存储的位置总是在reference字段所标识的对象的下一个位置。
(2)





get方法就是取出当前线程的localValues对象,然后找出其table数组中Reference对象的下一位置所存储的数据。就是ThreadLocal的值。
  因此在不同的线程中访问同一个ThreadLocal的set和get方法,所做的修改仅限于线程内部,所有ThreadLocal可以在多个线程中互不干扰地存储和修改数据。ThreadLocal在Looper中有用到。


3.消息队列MessageQueue
  MessageQueue主要包含两个操作:插入和读取。其内部实现并不是队列,是单链表,单链表在插入和删除比较有优势。
插入的方法:enqueueMessage()
读取的方法:next(),值得注意的是next()方法是一个无限循环的方法,有新消息时候,next方法会返回这条消息并且将其从单链表中移除。如果没有消息,就会一直阻塞在这里。

4.Looper的工作原理
  Looper具体就是他会不停地从MessageQueue中查看是否有新消息,如果有新消息就会立刻处理。
  Private Looper(boolean quitAllowed){
     mQueue = new MessageQueue(quitAllowed);
     mThread = Thread.currentThread(); 
}
Looper的构造方法会创建一个MessageQueue队列,Looper的主要方法有两个:
(1)Looper.prepare():为当前线程创建一个Looper,将其放入ThreadLocal中。
(2)Looper.loop():开启循环。从ThreadLocal中获取到当前线程的Looper,然后调用MessageQueue的next方法来获取新的消息。next是一个阻塞操作,没有消息时会阻塞在这里,这也会导致Looper.loop方法一直阻塞在这里,唯一是next返回为null时。当Looper.quit调用时,会调用MessageQueue的quit来通知退出。当Looper获取到消息时,会调用Handler的dispatchMessage方法来处理。这样子就切换到了Looper所在的线程。

5.Handler工作原理
  Handler的工作主要包括消息的发送和接收,无论是post还是sendmessage最终都是向消息队列中插入了一条消息。
当Looper开启循环,调用MessageQueue的next方法将消息传给Looper,Looper交由Handler.dispatchMessage处理。
 
DispatchMesaage方法就是Handler对消息的处理了:


1.首先查看Message的callback是否为空,callback其实就是一个Runnable对象,实际上就是Handler的post方法传递的Runnable参数。handleCallback中调用message.call.run()方法,但是并不是开启一个线程,这一点要注意。
2.检查mCallback是否为null,不为null就开始判断mCallback.handleMessage返回值为True,就会拦截消息。
否则就同3一样调用Handler的handleMessage来处理消息。
3.最后一种就是调用Handler的handleMessage方法来处理消息。
4.还有一种就是通过Looper来构造Handler,HandlerThread就需要这种构造方式来指定Looper。


6.主线程的消息循环
  在ActivityThread中,入口方法为main,在main方法中,系统会通过Looper.prepareMainLooper()来创建主线程的Looper以及MessageQueue,并且通过Looper.loop()来开启主线程的消息循环、


  AcitivityThread通过ApplicaitonThread和AMS进行进程间通信:AMS以进程间通信的方式完成ActivityThread的请求后会回调ApplicaitonThread中的Binder方法,然后Application Thread会向H发送消息,H收到消息后会将ApplicationThread中的逻辑切换到ActivityThread中即主线程中执行,这个过程就是主线程的消息循环模型。




猜你喜欢

转载自blog.csdn.net/qq_34028539/article/details/80337564