Android应用程序消息处理机制(Looper、Handler)分析(5)

简介:

      ActivityThread类的这个mH成员变量是什么时候创建的呢?我们前面在分析应用程序的消息循环时,说到当应用程序进程启动之后,就会加载ActivityThread类的main函数里面,在这个main函数里面,在通过Looper类进入消息循环之前,会在当前进程中创建一个ActivityThread实例:

  1. public final class ActivityThread {  
  2.     ......  
  3.   
  4.     public static final void main(String[] args) {  
  5.         ......  
  6.   
  7.         ActivityThread thread = new ActivityThread();  
  8.         thread.attach(false);  
  9.   
  10.         ......  
  11.     }  
  12. }  

 在创建这个实例的时候,就会同时创建其成员变量mH了:

  1. public final class ActivityThread {  
  2.     ......  
  3.   
  4.     final H mH = new H();  
  5.   
  6.     ......  
  7. }   

  前面说过,H类继承于Handler类,因此,当创建这个H对象时,会调用Handler类的构造函数,这个函数定义在frameworks/base/core/java/android/os/Handler.java文件中:

  1. public class Handler {  
  2.     ......  
  3.   
  4.     public Handler() {  
  5.         ......  
  6.   
  7.         mLooper = Looper.myLooper();  
  8.         ......  
  9.   
  10.         mQueue = mLooper.mQueue;  
  11.         ......  
  12.     }  
  13.   
  14.   
  15.     final MessageQueue mQueue;  
  16.     final Looper mLooper;  
  17.     ......  
  18. }  

   在Hanlder类的构造函数中,主要就是初始成员变量mLooper和mQueue了。这里的myLooper是Looper类的静态成员函数,通过它来获得一个Looper对象,这个Looper对象就是前面我们在分析消息循环时,在ActivityThread类的main函数中通过Looper.prepareMainLooper函数创建的。Looper.myLooper函数实现在frameworks/base/core/java/android/os/Looper.java文件中:

  1. public class Looper {  
  2.     ......  
  3.   
  4.     public static final Looper myLooper() {  
  5.         return (Looper)sThreadLocal.get();  
  6.     }  
  7.   
  8.     ......  
  9. }  

  有了这个Looper对象后,就可以通过Looper.mQueue来访问应用程序的消息队列了。

 

        有了这个Handler对象mH后,就可以通过它来往应用程序的消息队列中加入新的消息了。回到前面的queueOrSendMessage函数中,当它准备好了一个Message对象msg后,就开始调用mH.sendMessage函数来发送消息了,这个函数定义在frameworks/base/core/java/android/os/Handler.java文件中:

  1. public class Handler {  
  2.     ......  
  3.   
  4.     public final boolean sendMessage(Message msg)  
  5.     {  
  6.         return sendMessageDelayed(msg, 0);  
  7.     }  
  8.   
  9.     public final boolean sendMessageDelayed(Message msg, long delayMillis)  
  10.     {  
  11.         if (delayMillis < 0) {  
  12.             delayMillis = 0;  
  13.         }  
  14.         return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);  
  15.     }  
  16.   
  17.     public boolean sendMessageAtTime(Message msg, long uptimeMillis)  
  18.     {  
  19.         boolean sent = false;  
  20.         MessageQueue queue = mQueue;  
  21.         if (queue != null) {  
  22.             msg.target = this;  
  23.             sent = queue.enqueueMessage(msg, uptimeMillis);  
  24.         }  
  25.         else {  
  26.             ......  
  27.         }  
  28.         return sent;  
  29.     }  
  30.   
  31.     ......  
  32. }  

 

 

   在发送消息时,是可以指定消息的处理时间的,但是通过sendMessage函数发送的消息的处理时间默认就为当前时间,即表示要马上处理,因此,从sendMessage函数中调用sendMessageDelayed函数,传入的时间参数为0,表示这个消息不要延时处理,而在sendMessageDelayed函数中,则会先获得当前时间,然后加上消息要延时处理的时间,即得到这个处理这个消息的绝对时间,然后调用sendMessageAtTime函数来把消息加入到应用程序的消息队列中去。

 

        在sendMessageAtTime函数,首先得到应用程序的消息队列mQueue,这是在Handler对象构造时初始化好的,前面已经分析过了,接着设置这个消息的目标对象target,即这个消息最终是由谁来处理的:

 
 
  1. msg.target = this;   

 

   这里将它赋值为this,即表示这个消息最终由这个Handler对象来处理,即由ActivityThread对象的mH成员变量来处理。

 

 

 

        函数最后调用queue.enqueueMessage来把这个消息加入到应用程序的消息队列中去,这个函数实现在frameworks/base/core/java/android/os/MessageQueue.java文件中:

  1. public class MessageQueue {  
  2.     ......  
  3.   
  4.     final boolean enqueueMessage(Message msg, long when) {  
  5.         ......  
  6.   
  7.         final boolean needWake;  
  8.         synchronized (this) {  
  9.             ......  
  10.   
  11.             msg.when = when;  
  12.             //Log.d("MessageQueue", "Enqueing: " + msg);  
  13.             Message p = mMessages;  
  14.             if (p == null || when == 0 || when < p.when) {  
  15.                 msg.next = p;  
  16.                 mMessages = msg;  
  17.                 needWake = mBlocked; // new head, might need to wake up  
  18.             } else {  
  19.                 Message prev = null;  
  20.                 while (p != null && p.when <= when) {  
  21.                     prev = p;  
  22.                     p = p.next;  
  23.                 }  
  24.                 msg.next = prev.next;  
  25.                 prev.next = msg;  
  26.                 needWake = false; // still waiting on head, no need to wake up  
  27.             }  
  28.   
  29.         }  
  30.         if (needWake) {  
  31.             nativeWake(mPtr);  
  32.         }  
  33.         return true;  
  34.     }  
  35.   
  36.     ......  
  37. }  

 

   把消息加入到消息队列时,分两种情况,一种当前消息队列为空时,这时候应用程序的主线程一般就是处于空闲等待状态了,这时候就要唤醒它,另一种情况是应用程序的消息队列不为空,这时候就不需要唤醒应用程序的主线程了,因为这时候它一定是在忙着处于消息队列中的消息,因此不会处于空闲等待的状态。

 第一种情况比较简单,只要把消息放在消息队列头就可以了:

  1. msg.next = p;  
  2. mMessages = msg;  
  3. needWake = mBlocked; // new head, might need to wake up  

第二种情况相对就比较复杂一些了,前面我们说过,当往消息队列中发送消息时,是可以指定消息的处理时间的,而消息队列中的消息,就是按照这个时间从小到大来排序的,因此,当把新的消息加入到消息队列时,就要根据它的处理时间来找到合适的位置,然后再放进消息队列中去:

  1. Message prev = null;  
  2. while (p != null && p.when <= when) {  
  3.     prev = p;  
  4.     p = p.next;  
  5. }  
  6. msg.next = prev.next;  
  7. prev.next = msg;  
  8. needWake = false; // still waiting on head, no need to wake up  

把消息加入到消息队列去后,如果应用程序的主线程正处于空闲等待状态,就需要调用natvieWake函数来唤醒它了,这是一个JNI方法,定义在frameworks/base/core/jni/android_os_MessageQueue.cpp文件中:

  1. static void android_os_MessageQueue_nativeWake(JNIEnv* env, jobject obj, jint ptr) {  
  2.     NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);  
  3.     return nativeMessageQueue->wake();  
  4. }  

这个JNI层的NativeMessageQueue对象我们在前面分析消息循环的时候创建好的,保存在Java层的MessageQueue对象的mPtr成员变量中,这里把它取回来之后,就调用它的wake函数来唤醒应用程序的主线程,这个函数也是定义在frameworks/base/core/jni/android_os_MessageQueue.cpp文件中:

  1. void NativeMessageQueue::wake() {  
  2.     mLooper->wake();  
  3. }  

 这里它又通过成员变量mLooper的wake函数来执行操作,这里的mLooper成员变量是一个C++层实现的Looper对象,它定义在frameworks/base/libs/utils/Looper.cpp文件中:

  1. void Looper::wake() {  
  2.     ......  
  3.   
  4.     ssize_t nWrite;  
  5.     do {  
  6.         nWrite = write(mWakeWritePipeFd, "W", 1);  
  7.     } while (nWrite == -1 && errno == EINTR);  
  8.   
  9.     .......  
  10. }  

  这个wake函数很简单,只是通过打开文件描述符mWakeWritePipeFd往管道的写入一个"W"字符串。其实,往管道写入什么内容并不重要,往管道写入内容的目的是为了唤醒应用程序的主线程。前面我们在分析应用程序的消息循环时说到,当应用程序的消息队列中没有消息处理时,应用程序的主线程就会进入空闲等待状态,而这个空闲等待状态就是通过调用这个Looper类的pollInner函数来进入的,具体就是在pollInner函数中调用epoll_wait函数来等待管道中有内容可读的。

 

        这时候既然管道中有内容可读了,应用程序的主线程就会从这里的Looper类的pollInner函数返回到JNI层的nativePollOnce函数,最后返回到Java层中的MessageQueue.next函数中去,这里它就会发现消息队列中有新的消息需要处理了,于就会处理这个消息。





本文转自 Luoshengyang 51CTO博客,原文链接:http://blog.51cto.com/shyluo/966601,如需转载请自行联系原作者
目录
相关文章
|
存储 安全 Android开发
探索Android与iOS的隐私保护机制
在数字化时代,移动设备已成为我们生活的一部分,而隐私安全是用户最为关注的问题之一。本文将深入探讨Android和iOS两大主流操作系统在隐私保护方面的策略和实现方式,分析它们各自的优势和不足,以及如何更好地保护用户的隐私。
|
消息中间件 Android开发
Android Handler的使用方式以及其机制的简单介绍
Handler 是 Android 中实现线程间通信的重要机制,可传递任意两线程数据。常用场景包括子线程向主线程(UI 线程)传递结果,以及主线程向子线程发送消息。其核心涉及四个类:Handler(发送/接收消息)、Message(消息载体)、MessageQueue(消息队列)和 Looper(消息循环泵)。基本流程为:Handler 发送 Message 至 MessageQueue,Looper 从队列中按 FIFO 取出并处理。
523 0
|
Linux Android开发 iOS开发
深入探索Android与iOS的多任务处理机制
在移动操作系统领域,Android和iOS各有千秋,尤其在多任务处理上展现出不同的设计理念和技术实现。本文将深入剖析两大平台在后台管理、资源分配及用户体验方面的策略差异,揭示它们如何平衡性能与电池寿命,为用户带来流畅而高效的操作体验。通过对比分析,我们不仅能够更好地理解各自系统的工作机制,还能为开发者优化应用提供参考。
|
算法 Linux 调度
深入探索安卓系统的多任务处理机制
【10月更文挑战第21天】 本文旨在为读者提供一个关于Android系统多任务处理机制的全面解析。我们将从Android操作系统的核心架构出发,探讨其如何管理多个应用程序的同时运行,包括进程调度、内存管理和电量优化等方面。通过深入分析,本文揭示了Android在处理多任务时所面临的挑战以及它如何通过创新的解决方案来提高用户体验和设备性能。
1127 1
|
消息中间件 存储 Java
Android面试高频知识点(2) 详解Android消息处理机制(Handler)
Android面试高频知识点(2) 详解Android消息处理机制(Handler)
|
移动开发 安全 Android开发
构建高效Android应用:Kotlin协程的实践与优化策略
【5月更文挑战第30天】 在移动开发领域,性能优化始终是关键议题之一。特别是对于Android开发者来说,如何在保证应用流畅性的同时,提升代码的执行效率,已成为不断探索的主题。近年来,Kotlin语言凭借其简洁、安全和实用的特性,在Android开发中得到了广泛的应用。其中,Kotlin协程作为一种新的并发处理机制,为编写异步、非阻塞性的代码提供了强大工具。本文将深入探讨Kotlin协程在Android开发中的应用实践,以及如何通过协程优化应用性能,帮助开发者构建更高效的Android应用。
|
移动开发 API Android开发
构建高效Android应用:探究Kotlin协程的优势与实践
【5月更文挑战第17天】在移动开发领域,性能优化和流畅的用户体验一直是开发者追求的目标。针对Android平台,Kotlin语言凭借其简洁性和功能丰富性成为了许多开发者的首选。其中,Kotlin协程作为异步编程的强大工具,为处理并发任务提供了轻量级的解决方案。本文深入探讨了Kotlin协程的核心优势,并通过实例分析其在Android开发中的应用,旨在帮助开发者提升应用的性能和响应能力。
|
API 调度 Android开发
打造高效Android应用:探究Kotlin协程的优势与实践
【5月更文挑战第27天】在移动开发领域,性能优化和响应速度是衡量应用质量的关键因素。随着Kotlin语言的普及,协程作为其核心特性之一,为Android开发者提供了一种全新的并发处理方式。本文深入探讨了Kotlin协程在Android应用开发中的优势,并通过实例演示如何在实际项目中有效利用协程提升应用性能和用户体验。
|
移动开发 Android开发 开发者
构建高效Android应用:探究Kotlin协程的优势与实践
【5月更文挑战第21天】在移动开发领域,性能优化和流畅的用户体验是至关重要的。随着Kotlin语言在Android平台的广泛采纳,其并发处理的强大工具—协程(Coroutines),已成为提升应用响应性和效率的关键因素。本文将深入分析Kotlin协程的核心原理,探讨其在Android开发中的优势,并通过实例演示如何有效利用协程来优化应用性能,打造更加流畅的用户体验。
290 4
|
物联网 区块链 Android开发
构建高效Android应用:Kotlin与Jetpack的实践之路未来技术的融合潮流:区块链、物联网与虚拟现实的交汇点
【5月更文挑战第30天】 在移动开发领域,效率和性能始终是开发者追求的核心。随着技术的不断进步,Kotlin语言以其简洁性和现代化特性成为Android开发的新宠。与此同时,Jetpack组件为应用开发提供了一套经过实践检验的库、工具和指南,旨在简化复杂任务并帮助提高应用质量。本文将深入探索如何通过Kotlin结合Jetpack组件来构建一个既高效又稳定的Android应用,并分享在此过程中的最佳实践和常见陷阱。

热门文章

最新文章