Android的handler消息机制

时间:2022-06-21 09:45:27

  Hnadler机制中有这么几部分构成,包括 handler、Message、Looper和MessageQueue。要想在一个线程中使用Handler的话必须要有Looper和MessageQueue 的对象。在主线程中Looper不需要我们去创建 系统会自动帮我们调用prepareMainLooper和Looper.prepare方法,looper.prepare首先会到ThreadLocal这个线程级的单例中判断是否已经有了looper对象,如果有了就抛异常,如果没有就new出一个新的对象,并且通过ThreadLocal保存起来。这样就确保了我们的looper对象和当前线程建立起了一一对应的关系。looper对象new自己的时候调用构造方法会创建一个messageQueue对象,并且通过一个final类型的成员变量把MessageQueue保存起来。这样就确保了一个Looper对应唯一的messageQueue。所以 一个线程最多只能有一个looper, 一个looper对应唯一的MessageQueueu。也就是一个线程有唯一的Looper唯一的messageQueue。MessageQueue在创建的过程中会调用nativeInit方法,创建出一个nativeMessageQueue也就是说在jni层也有一个MessageQueue 创建NativeMessaageQueue的时候还会创建一个C++的Looper java层的MessageQueue和NativeMessageQueue通过一个成员变量mPtr建立起关联 mPtr保存了nativeMessageQueue的指针,我们可以通过这个指针随时访问nativeMessageQueue的首地址。需要注意 如果在主线程中调用Looper.prepareMainLooper或者Looper.prepare() 程序会抛出异常,因为系统已经帮我们创建好了无需我们在创建。
looper和messageQueue创建完成之后需要调用Looper.loop让消息循环起来。Looper.loop中有一个死循环,死循环不会阻塞主线程,而且恰恰是因为有这个死循环是我的主线程的代码不会执行完。handler不断的往消息队列中发消息 looper不断的取消息,如果没有消息就会睡在
Message msg = queue.next方法。实际上就是调用了nativeMessageQueue的方法, 利用到了linuxs的管道机制,取出消息之后就通过handler调用disPatchMessage来分发消息。他有三种情况:
如果msg的callback不为空 消息交给这个callback处理
如果msg的callback为空 判断handler mCallback接口 这个接口中就一个方法handleMessage
如果这个callback不为空交给这个handleMessage处理
如果上面两个都为空才交给handler的handleMessage处理消息

  创建handler的时候 先到当前的线程中获取looper,如果当前线程没有looper的话那么会抛异常,如果当前线程已经创建了looper,那么我们把这个looper保存到一个final类型的成员变量中,通过这个Lopper找到对应的messageQueue,通过final成员变量进行保存这个messageQueue。这样就可以确保我们在哪个线程创建的handler,消息就会发送到对应的messageQueue中去。如果想在子线程中使用handler,必须首先调用looper.prepare()方法。

handler发送消息:  

  sendMessage sendEmptyMessage... 实际上都是调用 sendMessageAtTime这个方法,sendMessageAtTime调用了qnqueueMessage方法,这个党法实际上就是把消息放到消息队列中,

消息如何在消息队列中排序:
  实际上Messagequeue通过一个成员变量 mMessage保存了消息队列的第一条消息,消息在消息队列中的排序是根据消息要执行的时间先后顺序进行排序。先执行的消息排在前面的,下一条消息通过message的next属性进行保存。enqueueMessage 就是根据新加入进来的消息 要执行的时间跟已有的消息进行比较找到合适的位置放到消息队列中。如果消息需要立即执行,那么就会执行nativeWake方法,实际上就是向管道中写了一个w 那么messageQueue的next方法就不会阻塞可以取出消息。

消息的创建和回收:

  如果使用obtain方法来获取消息,那么就会利用到android的消息池。注意这个消息池是全局的,消息池的大小为50条。消息的回收,在Looper.loop()方法中当Handler处理消息之后会调用message.recycle方法回收消息。把要回收的消息所有的成员变量恢复到刚new出来的状态,然后放到消息池中去。