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

简介:

    Android应用程序是通过消息来驱动的,系统为每一个应用程序维护一个消息队例,应用程序的主线程不断地从这个消息队例中获取消息(Looper),然后对这些消息进行处理(Handler),这样就实现了通过消息来驱动应用程序的执行,本文将详细分析Android应用程序的消息处理机制。

        前面我们学习Android应用程序中的Activity启动(Android应用程序启动过程源代码分析Android应用程序内部启动Activity过程(startActivity)的源代码分析)、Service启动(Android系统在新进程中启动自定义服务过程(startService)的原理分析Android应用程序绑定服务(bindService)的过程源代码分析)以及广播发送(Android应用程序发送广播(sendBroadcast)的过程分析)时,它们都有一个共同的特点,当ActivityManagerService需要与应用程序进行并互时,如加载Activity和Service、处理广播待,会通过Binder进程间通信机制来知会应用程序,应用程序接收到这个请求时,它不是马上就处理这个请求,而是将这个请求封装成一个消息,然后把这个消息放在应用程序的消息队列中去,然后再通过消息循环来处理这个消息。这样做的好处就是消息的发送方只要把消息发送到应用程序的消息队列中去就行了,它可以马上返回去处理别的事情,而不需要等待消息的接收方去处理完这个消息才返回,这样就可以提高系统的并发性。实质上,这就是一种异步处理机制。

        这样说可能还是比较笼统,我们以Android应用程序启动过程源代码分析一文中所介绍的应用程序启动过程的一个片断来具体看看是如何这种消息处理机制的。在这篇文章中,要启动的应用程序称为Activity,它的默认Activity是MainActivity,它是由Launcher来负责启动的,而Launcher又是通过ActivityManagerService来启动的,当ActivityManagerService为这个即将要启的应用程序准备好新的进程后,便通过一个Binder进程间通信过程来通知这个新的进程来加载MainActivity,如下图所示:

    它对应Android应用程序启动过程中的Step 30到Step 35,有兴趣的读者可以回过头去参考Android应用程序启动过程源代码分析一文。这里的Step 30中的scheduleLaunchActivity是ActivityManagerService通过Binder进程间通信机制发送过来的请求,它请求应用程序中的ActivityThread执行Step 34中的performLaunchActivity操作,即启动MainActivity的操作。这里我们就可以看到,Step 30的这个请求并没有等待Step 34这个操作完成就返回了,它只是把这个请求封装成一个消息,然后通过Step 31中的queueOrSendMessage操作把这个消息放到应用程序的消息队列中,然后就返回了。应用程序发现消息队列中有消息时,就会通过Step 32中的handleMessage操作来处理这个消息,即调用Step 33中的handleLaunchActivity来执行实际的加载MainAcitivy类的操作。

        了解Android应用程序的消息处理过程之后,我们就开始分样它的实现原理了。与Windows应用程序的消息处理过程一样,Android应用程序的消息处理机制也是由消息循环、消息发送和消息处理这三个部分组成的,接下来,我们就详细描述这三个过程。

        1. 消息循环

        在消息处理机制中,消息都是存放在一个消息队列中去,而应用程序的主线程就是围绕这个消息队列进入一个无限循环的,直到应用程序退出。如果队列中有消息,应用程序的主线程就会把它取出来,并分发给相应的Handler进行处理;如果队列中没有消息,应用程序的主线程就会进入空闲等待状态,等待下一个消息的到来。在Android应用程序中,这个消息循环过程是由Looper类来实现的,它定义在frameworks/base/core/java/android/os/Looper.java文件中,在分析这个类之前,我们先看一下Android应用程序主线程是如何进入到这个消息循环中去的。

        在Android应用程序进程启动过程的源代码分析一文中,我们分析了Android应用程序进程的启动过程,Android应用程序进程在启动的时候,会在进程中加载ActivityThread类,并且执行这个类的main函数,应用程序的消息循环过程就是在这个main函数里面实现的,我们来看看这个函数的实现,它定义在frameworks/base/core/java/android/app/ActivityThread.java文件中:

  1. public final class ActivityThread {  
  2.     ......  
  3.   
  4.     public static final void main(String[] args) {  
  5.         ......  
  6.   
  7.         Looper.prepareMainLooper();  
  8.   
  9.         ......  
  10.   
  11.         ActivityThread thread = new ActivityThread();  
  12.         thread.attach(false);  
  13.           
  14.         ......  
  15.   
  16.         Looper.loop();  
  17.   
  18.         ......  
  19.   
  20.         thread.detach();  
  21.   
  22.         ......  
  23.     }  
  24. }  

       这个函数做了两件事情,一是在主线程中创建了一个ActivityThread实例,二是通过Looper类使主线程进入消息循环中,这里我们只关注后者。

 

        首先看Looper.prepareMainLooper函数的实现,这是一个静态成员函数,定义在frameworks/base/core/java/android/os/Looper.java文件中:

  1. public class Looper {  
  2.     ......  
  3.   
  4.     private static final ThreadLocal sThreadLocal = new ThreadLocal();  
  5.   
  6.     final MessageQueue mQueue;  
  7.   
  8.     ......  
  9.   
  10.     /** Initialize the current thread as a looper. 
  11.     * This gives you a chance to create handlers that then reference 
  12.     * this looper, before actually starting the loop. Be sure to call 
  13.     * {@link #loop()} after calling this method, and end it by calling 
  14.     * {@link #quit()}. 
  15.     */  
  16.     public static final void prepare() {  
  17.         if (sThreadLocal.get() != null) {  
  18.             throw new RuntimeException("Only one Looper may be created per thread");  
  19.         }  
  20.         sThreadLocal.set(new Looper());  
  21.     }  
  22.   
  23.     /** Initialize the current thread as a looper, marking it as an application's main  
  24.     *  looper. The main looper for your application is created by the Android environment, 
  25.     *  so you should never need to call this function yourself. 
  26.     * {@link #prepare()} 
  27.     */  
  28.   
  29.     public static final void prepareMainLooper() {  
  30.         prepare();  
  31.         setMainLooper(myLooper());  
  32.         if (Process.supportsProcesses()) {  
  33.             myLooper().mQueue.mQuitAllowed = false;  
  34.         }  
  35.     }  
  36.   
  37.     private synchronized static void setMainLooper(Looper looper) {  
  38.         mMainLooper = looper;  
  39.     }  
  40.   
  41.     /** 
  42.     * Return the Looper object associated with the current thread.  Returns 
  43.     * null if the calling thread is not associated with a Looper. 
  44.     */  
  45.     public static final Looper myLooper() {  
  46.         return (Looper)sThreadLocal.get();  
  47.     }  
  48.   
  49.     private Looper() {  
  50.         mQueue = new MessageQueue();  
  51.         mRun = true;  
  52.         mThread = Thread.currentThread();  
  53.     }  
  54.   
  55.     ......  
  56. }  

        函数prepareMainLooper做的事情其实就是在线程中创建一个Looper对象,这个Looper对象是存放在sThreadLocal成员变量里面的,成员变量sThreadLocal的类型为ThreadLocal,表示这是一个线程局部变量,即保证每一个调用了prepareMainLooper函数的线程里面都有一个独立的Looper对象。在线程是创建Looper对象的工作是由prepare函数来完成的,而在创建Looper对象的时候,会同时创建一个消息队列MessageQueue,保存在Looper的成员变量mQueue中,后续消息就是存放在这个队列中去。消息队列在Android应用程序消息处理机制中最重要的组件,因此,我们看看它的创建过程,即它的构造函数的实现,实现frameworks/base/core/java/android/os/MessageQueue.java文件中:

  1. public class MessageQueue {  
  2.     ......  
  3.   
  4.     private int mPtr; // used by native code  
  5.   
  6.     private native void nativeInit();  
  7.   
  8.     MessageQueue() {  
  9.         nativeInit();  
  10.     }  
  11.   
  12.     ......  
  13. }  

    它的初始化工作都交给JNI方法nativeInit来实现了,这个JNI方法定义在frameworks/base/core/jni/android_os_MessageQueue.cpp文件中:

  1. static void android_os_MessageQueue_nativeInit(JNIEnv* env, jobject obj) {  
  2.     NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();  
  3.     if (! nativeMessageQueue) {  
  4.         jniThrowRuntimeException(env, "Unable to allocate native queue");  
  5.         return;  
  6.     }  
  7.   
  8.     android_os_MessageQueue_setNativeMessageQueue(env, obj, nativeMessageQueue);  
  9. }  

    在JNI中,也相应地创建了一个消息队列NativeMessageQueue,NativeMessageQueue类也是定义在frameworks/base/core/jni/android_os_MessageQueue.cpp文件中,它的创建过程如下所示:

  1. NativeMessageQueue::NativeMessageQueue() {  
  2.     mLooper = Looper::getForThread();  
  3.     if (mLooper == NULL) {  
  4.         mLooper = new Looper(false);  
  5.         Looper::setForThread(mLooper);  
  6.     }  
  7. }  

   它主要就是在内部创建了一个Looper对象,注意,这个Looper对象是实现在JNI层的,它与上面Java层中的Looper是不一样的,不过它们是对应的,下面我们进一步分析消息循环的过程的时候,读者就会清楚地了解到它们之间的关系。

 

        这个Looper的创建过程也很重要,不过我们暂时放一放,先分析完android_os_MessageQueue_nativeInit函数的执行,它创建了本地消息队列NativeMessageQueue对象之后,接着调用android_os_MessageQueue_setNativeMessageQueue函数来把这个消息队列对象保存在前面我们在Java层中创建的MessageQueue对象的mPtr成员变量里面:

  1. static void android_os_MessageQueue_setNativeMessageQueue(JNIEnv* env, jobject messageQueueObj,  
  2.         NativeMessageQueue* nativeMessageQueue) {  
  3.     env->SetIntField(messageQueueObj, gMessageQueueClassInfo.mPtr,  
  4.              reinterpret_cast<jint>(nativeMessageQueue));  
  5. }  

    这里传进来的参数messageQueueObj即为我们前面在Java层创建的消息队列对象,而gMessageQueueClassInfo.mPtr即表示在Java类MessageQueue中,其成员变量mPtr的偏移量,通过这个偏移量,就可以把这个本地消息队列对象natvieMessageQueue保存在Java层创建的消息队列对象的mPtr成员变量中,这是为了后续我们调用Java层的消息队列对象的其它成员函数进入到JNI层时,能够方便地找回它在JNI层所对应的消息队列对象。





本文转自 Luoshengyang 51CTO博客,原文链接:http://blog.51cto.com/shyluo/966586,如需转载请自行联系原作者

目录
相关文章
|
3天前
|
移动开发 监控 前端开发
构建高效Android应用:从优化布局到提升性能
【7月更文挑战第60天】在移动开发领域,一个流畅且响应迅速的应用程序是用户留存的关键。针对Android平台,开发者面临的挑战包括多样化的设备兼容性和性能优化。本文将深入探讨如何通过改进布局设计、内存管理和多线程处理来构建高效的Android应用。我们将剖析布局优化的细节,并讨论最新的Android性能提升策略,以帮助开发者创建更快速、更流畅的用户体验。
21 10
|
3天前
|
Android开发
基于android-11.0.0_r39,系统应用的手动签名方法和过程
本文介绍了基于Android 11.0.0_r39版本进行系统应用手动签名的方法和解决签名过程中遇到的错误,包括处理`no conscrypt_openjdk_jni-linux-x86_64`和`RegisterNatives failed`的问题。
27 2
|
1天前
|
供应链 物联网 区块链
未来触手可及:探索新兴技术的趋势与应用安卓开发中的自定义视图:从基础到进阶
【8月更文挑战第30天】随着科技的飞速发展,新兴技术如区块链、物联网和虚拟现实正在重塑我们的世界。本文将深入探讨这些技术的发展趋势和应用场景,带你领略未来的可能性。
|
2天前
|
人工智能 缓存 数据库
安卓应用开发中的性能优化技巧AI在医疗诊断中的应用
【8月更文挑战第29天】在安卓开发的广阔天地里,性能优化是提升用户体验、确保应用流畅运行的关键所在。本文将深入浅出地探讨如何通过代码优化、资源管理和异步处理等技术手段,有效提升安卓应用的性能表现。无论你是初学者还是资深开发者,这些实用的技巧都将为你的安卓开发之路增添光彩。
|
2天前
|
搜索推荐 开发工具 Android开发
打造个性化安卓应用:从零开始的Flutter之旅
【8月更文挑战第29天】在这个数字时代,个性化的应用成为了展示自我风格的一种方式。本文将引导你通过Flutter框架,一步步构建属于你的首个安卓应用。我们将探索Flutter的核心概念,界面设计,以及如何将你的创意转化为现实。无论你是编程新手还是希望扩展技能的开发者,这篇文章都将为你提供价值。让我们一起踏上这段创造性的旅程吧!
|
10天前
|
存储 安全 物联网
Android经典实战之跳转到系统设置页面或其他系统应用页面大全
本文首发于公众号“AntDream”,关注获取更多技巧。文章总结了Android开发中跳转至系统设置页面的方法,包括设备信息、Wi-Fi、显示与声音设置等,并涉及应用详情与电池优化页面。通过简单的Intent动作即可实现,需注意权限与版本兼容性。每日进步,尽在“AntDream”。
39 2
|
11天前
|
开发框架 Android开发 Swift
安卓与iOS应用开发对比分析
【8月更文挑战第20天】在移动应用开发的广阔天地中,安卓和iOS两大平台各占半壁江山。本文将深入探讨这两大操作系统在开发环境、编程语言、用户界面设计、性能优化及市场分布等方面的差异和特点。通过比较分析,旨在为开发者提供一个宏观的视角,帮助他们根据项目需求和目标受众选择最合适的开发平台。同时,文章还将讨论跨平台开发框架的利与弊,以及它们如何影响着移动应用的开发趋势。
|
1天前
|
JSON 缓存 搜索推荐
探索安卓开发:打造个性化天气应用探索移动应用开发之旅:从基础到高级
【8月更文挑战第30天】在数字化时代,智能手机已成为我们日常生活中不可或缺的一部分。安卓系统以其开放性和灵活性赢得了全球用户的青睐。本文将引导你了解如何利用安卓开发技术,从零开始构建一个具有个性化特色的天气应用。我们将一起深入探讨应用的设计思路、核心功能实现以及用户交互体验的优化方法。无论你是编程新手还是有一定经验的开发者,这篇文章都将为你提供有价值的指导和灵感。
|
1天前
|
物联网 区块链 vr&ar
未来已来:探索区块链、物联网与虚拟现实技术的融合与应用安卓与iOS开发中的跨平台框架选择
【8月更文挑战第30天】在科技的巨轮下,新技术不断涌现,引领着社会进步。本文将聚焦于当前最前沿的技术——区块链、物联网和虚拟现实,探讨它们各自的发展趋势及其在未来可能的应用场景。我们将从这些技术的基本定义出发,逐步深入到它们的相互作用和集成应用,最后展望它们如何共同塑造一个全新的数字生态系统。
|
5天前
|
缓存 监控 Android开发
构建高效的Android应用:从内存优化到用户体验
【7月更文挑战第57天】 在竞争激烈的移动市场中,一个高效、流畅且具有优秀用户体验的Android应用是成功的关键。本文将深入探讨如何通过内存管理和界面优化来提升应用性能,包括实用的编程技巧和策略,以及如何利用Android系统提供的工具进行调试和性能监控。读者将学习到如何识别和解决常见的性能瓶颈,以及如何设计出既美观又实用的用户界面。