Android应用程序键盘(Keyboard)消息处理机制分析(23)

简介:

 Step 39. InputConsumer.sendFinishedSignal

       这个函数定义在frameworks/base/libs/ui/InputTransport.cpp文件中:

  1. status_t InputConsumer::sendFinishedSignal() {  
  2.     ......  
  3.   
  4.     return mChannel->sendSignal(INPUT_SIGNAL_FINISHED);  
  5. }  

        这个函数的实现很简单,只是调用其内部对象mChannel的sendSignal函数来执行发送信号的通知。前面我们已经说过,这里的mChannel的类型为InputChannel,它是注册在应用程序一侧的Client端InputChannel,它的成员函数sendSignal的定义我们在上面的Step 20中已经分析过了,这里不再详述,不过,这里和上面Step 20不一样的地方是,它里的通知方向是从反向管道的写端(在应用程序这一侧)到反向管道的读端(在InputDispatcher这一侧)。

 

        前面我们在分析应用程序注册键盘消息接收通道的过程时,在Step 18(InputDispatcher.registerInputChannel)中,说到InputDispatcher把一个反向管道的读端文件描述符添加到WindowManagerService所运行的线程中的Looper对象中去,然后就会在这个反向管道的读端上睡眠等待有这个管道有新的内容可读。现在,InputConsumer往这个反向管道写入新的内容了,于是,InputDispatcher就被唤醒过来了,唤醒过来后,它所调用的函数是InputDispatcher.handleReceiveCallback函数,这与前面的Step 21的逻辑是一样的。

       Step 40. InputDispatcher.handleReceiveCallack

       这个函数定义在frameworks/base/libs/ui/InputDispatcher.cpp文件中:

  1. int InputDispatcher::handleReceiveCallback(int receiveFd, int events, void* data) {  
  2.     InputDispatcher* d = static_cast<InputDispatcher*>(data);  
  3.   
  4.     { // acquire lock  
  5.         AutoMutex _l(d->mLock);  
  6.   
  7.         ssize_t connectionIndex = d->mConnectionsByReceiveFd.indexOfKey(receiveFd);  
  8.         ......  
  9.   
  10.         nsecs_t currentTime = now();  
  11.   
  12.         sp<Connection> connection = d->mConnectionsByReceiveFd.valueAt(connectionIndex);  
  13.         ......  
  14.   
  15.         status_t status = connection->inputPublisher.receiveFinishedSignal();  
  16.         if (status) {  
  17.             ......  
  18.             return 0; // remove the callback  
  19.         }  
  20.   
  21.         d->finishDispatchCycleLocked(currentTime, connection);  
  22.         ......  
  23.   
  24.         return 1;  
  25.     } // release lock  
  26. }  

        这个函数首先是通过传进来的receiveFd参数(反向管道的读端文件描述符)的值取得相应的Connection对象:

  1. ssize_t connectionIndex = d->mConnectionsByReceiveFd.indexOfKey(receiveFd);  
  2.      ......  
  3.   
  4. sp<Connection> connection = d->mConnectionsByReceiveFd.valueAt(connectionIndex);  

        然后通过调用这个connection对象的内部对象inputPublisher的receiveFinishedSignal函数来确认是否真的收到键盘事件处理完成的信号,确认之后,就会调用InputDispatcher对象d的finishDispatchCycleLocked函数来执行一些善后工作。下面我们就依次分析这两个过程。

 

        Step 41. InputPublisher.receiverFinishedSignal

        这个函数定义在frameworks/base/libs/ui/InputTransport.cpp文件中:

  1. status_t InputPublisher::receiveFinishedSignal() {  
  2.     ....  
  3.   
  4.     char signal;  
  5.     status_t result = mChannel->receiveSignal(& signal);  
  6.     if (result) {  
  7.         return result;  
  8.     }  
  9.     if (signal != INPUT_SIGNAL_FINISHED) {  
  10.         .......  
  11.         return UNKNOWN_ERROR;  
  12.     }  
  13.     return OK;  
  14. }  

        这里的逻辑和前面的Step 22中NativeInputQueue确认是否真的收到键盘事件分发的信号的逻辑是一致的,都是通过InputChannel的receiveSignal函数来确认是否在管道中收到了某一个约定的字符值,不过,这里约定的字符值为INPUT_SIGNAL_FINISHED。

 

        回到前面的Step 40中,确认了是真的收到了键盘事件处理完成的信号后,就调用InputDispatcher的finishDispatchCycleLocked函数来执行一些善后工作了。

        Step 42. InputDispatcher.finishDispatchCycleLocked
        这个函数定义在frameworks/base/libs/ui/InputDispatcher.cpp文件中:

  1. void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime,  
  2.         const sp<Connection>& connection) {  
  3.     ......  
  4.   
  5.     // Notify other system components.  
  6.     onDispatchCycleFinishedLocked(currentTime, connection);  
  7.   
  8.     // Reset the publisher since the event has been consumed.  
  9.     // We do this now so that the publisher can release some of its internal resources  
  10.     // while waiting for the next dispatch cycle to begin.  
  11.     status_t status = connection->inputPublisher.reset();  
  12.     ......  
  13.   
  14.     startNextDispatchCycleLocked(currentTime, connection);  
  15. }  

        这个函数主要就是做了三件事情:

 

       一是通知其它系统,InputDispatcher完成了一次键盘事件的处理:

  1. // Notify other system components.  
  2. onDispatchCycleFinishedLocked(currentTime, connection);  

        二是调用相应的connection对象的内部对象inputPublisher来的reset函数来回收一些资源,它里面其实就是释放前面在Step 18(InputPublisher.publishKeyEvent)使用的匿名共享内存了:

  1. // Reset the publisher since the event has been consumed.  
  2. // We do this now so that the publisher can release some of its internal resources  
  3. // while waiting for the next dispatch cycle to begin.  
  4. status_t status = connection->inputPublisher.reset();  

        三是调用InputDispatcher的startNextDispatchCycleLocked函数来处理下一个键盘事件:

  1. startNextDispatchCycleLocked(currentTime, connection);  

        因为正在处理当前这个键盘事件的时候,很有可能又同时发生了其它的键盘事件,因此,这里InputDispatcher还不能停下来,需要继续调用startNextDispatchCycleLocked继续处理键盘事件,不过下一个键盘事件的处理过程和我们现在分析的过程就是一样的了。

 

        至此,InputManager分发键盘消息给应用程序的过程就分析完成了,这是一个比较复杂的过程,不过,只要我们抓住主要的线索,就不难理解了,现在我们就小结一下这个过程的四个主要线索:

        A. 键盘事件发生,InputManager中的InputReader被唤醒,此前InputReader睡眠在/dev/input/event0这个设备文件上;

        B. InputReader被唤醒后,它接着唤醒InputManager中的InputDispatcher,此前InputDispatcher睡眠在InputManager所运行的线程中的Looper对象里面的管道的读端上;

        C. InputDispatcher被唤醒后,它接着唤醒应用程序的主线程来处理这个键盘事件,此前应用程序的主线程睡眠在Client端InputChannel中的前向管道的读端上;

        D. 应用程序处理处理键盘事件之后,它接着唤醒InputDispatcher来执行善后工作,此前InputDispatcher睡眠在Server端InputChannel的反向管道的读端上,注意这里与第二个线索处的区别。





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

热门文章

最新文章