Step 14.NativeInputQueue.unregisterInputChannel

这个函数定义在frameworks/base/core/jni/android_view_InputQueue.cpp文件中:

  1. status_tNativeInputQueue::unregisterInputChannel(JNIEnv*env,jobjectinputChannelObj){
  2. sp<InputChannel>inputChannel=android_view_InputChannel_getInputChannel(env,
  3. inputChannelObj);
  4. ......
  5. {//acquirelock
  6. AutoMutex_l(mLock);
  7. ssize_tconnectionIndex=getConnectionIndex(inputChannel);
  8. ......
  9. sp<Connection>connection=mConnectionsByReceiveFd.valueAt(connectionIndex);
  10. mConnectionsByReceiveFd.removeItemsAt(connectionIndex);
  11. connection->status=Connection::STATUS_ZOMBIE;
  12. connection->looper->removeFd(inputChannel->getReceivePipeFd());
  13. env->DeleteGlobalRef(connection->inputHandlerObjGlobal);
  14. connection->inputHandlerObjGlobal=NULL;
  15. ......
  16. }//releaselock
  17. ......
  18. returnOK;
  19. }

真正的注销工作就是这里实现的了,读者可以对照前面介绍应用程序注册键盘消息接收通道过程中的Step 21(NativeInputQueue.registerInputChannel)来分析,它首先是将在之前创建的Connection对象从NativeInputQueue中的mConnectionByReceiveFd向量中删除:

  1. ssize_tconnectionIndex=getConnectionIndex(inputChannel);
  2. ......
  3. sp<Connection>connection=mConnectionsByReceiveFd.valueAt(connectionIndex);
  4. mConnectionsByReceiveFd.removeItemsAt(connectionIndex);

然后再把这个Client端InputChannel的前向管道的读端文件描述符从应用程序主线程中的Looper对象中删除:

  1. connection->looper->removeFd(inputChannel->getReceivePipeFd());

这样,这个Activity窗口以后就不会接收到键盘事件了。

最后将Connection对象中的回调对象inputHandlerOjbGlobal对象删除:

  1. env->DeleteGlobalRef(connection->inputHandlerObjGlobal);
  2. connection->inputHandlerObjGlobal=NULL;

回忆一下前面我们在分析InputManager分发键盘消息给应用程序处理时,曾经说到,每当有键盘事件发生时,InputManager首先就会调用NativeInputQueue类的handleReceiveCallback函数。在这个handleReceiveCallback函数里面,NativeInputQueue会找到相应的Connection对象,然后把它里面的内部对象inputHandlerOjbGlobal作为参数来调用Java层的InputQueue类的dispatchKeyEvent函数来通知应用程序,有键盘事件发生了。在InputQueue类的dispatchKeyEvent函数里面,就是通过这个inputHandlerOjbGlobal对象来直正通知到当前激活的Activity窗口来处理这个键盘事件的。

注册在应用程序这一侧的Client端InputChannel被注销以后,回到前面的Step 11中,我们继续分析注销注册在InputManager这一侧的Server端InputChannel。Step 15. WindowManagerService.Session.remove

这个函数定义在frameworks/base/services/java/com/android/server/WindowManagerService.java文件中:

  1. publicclassWindowManagerServiceextendsIWindowManager.Stub
  2. implementsWatchdog.Monitor{
  3. ......
  4. privatefinalclassSessionextendsIWindowSession.Stub
  5. implementsIBinder.DeathRecipient{
  6. ......
  7. publicvoidremove(IWindowwindow){
  8. removeWindow(this,window);
  9. }
  10. ......
  11. }
  12. ......
  13. }

这个函数只是简单地调用其外部类WindowManagerService的removeWindow函数来进一步执行操作。

Step 16.WindowManagerService.removeWindow
这个函数定义在frameworks/base/services/java/com/android/server/WindowManagerService.java文件中:

  1. publicclassWindowManagerServiceextendsIWindowManager.Stub
  2. implementsWatchdog.Monitor{
  3. ......
  4. publicvoidremoveWindow(Sessionsession,IWindowclient){
  5. synchronized(mWindowMap){
  6. WindowStatewin=windowForClientLocked(session,client,false);
  7. if(win==null){
  8. return;
  9. }
  10. removeWindowLocked(session,win);
  11. }
  12. }
  13. ......
  14. }

回忆一下前面我们在分析应用程序注册键盘消息管道的过程时,在Step 11(WindowManagerService.addWindow)中,WindowManagerService为这个即将要激活的Activity窗口创建了一个WindowState对象win,创建的时候,使用了从ViewRoot中传过来的两个参数,分别是一个Session对象session和一个IWindow对象client。

在这个函数中,ViewRoot传过来的两个参数session和client和上面说的两个参数是一致的,因此,这个函数首先通过参数session和client得到一个WindowState对象win,然后调用removeWindowLocked来把它从WindowManagerService删除。

Step 17.WindowManagerService.removeWindowLocked
这个函数定义在frameworks/base/services/java/com/android/server/WindowManagerService.java文件中:

  1. publicclassWindowManagerServiceextendsIWindowManager.Stub
  2. implementsWatchdog.Monitor{
  3. ......
  4. publicvoidremoveWindowLocked(Sessionsession,WindowStatewin){
  5. ......
  6. win.disposeInputChannel();
  7. ......
  8. }
  9. ......
  10. }

我们忽略了这个函数的其它逻辑,只关注注销之前注册的Server端InputChannel的逻辑,这里,注销的操作就是调用win的disposeInputChannel进行的了。

Step 18. WindowState.disposeInputChannel

这个函数定义在frameworks/base/services/java/com/android/server/WindowManagerService.java文件中:

  1. publicclassWindowManagerServiceextendsIWindowManager.Stub
  2. implementsWatchdog.Monitor{
  3. ......
  4. privatefinalclassWindowStateimplementsWindowManagerPolicy.WindowState{
  5. ......
  6. voiddisposeInputChannel(){
  7. if(mInputChannel!=null){
  8. mInputManager.unregisterInputChannel(mInputChannel);
  9. mInputChannel.dispose();
  10. mInputChannel=null;
  11. }
  12. }
  13. ......
  14. }
  15. ......
  16. }
上面说到,在前面分析应用程序注册键盘消息管道的过程时,在Step 11(WindowManagerService.addWindow)中,为当前这个Activity窗口创建了一个WindowState对象,接着创建了一个输入管道后,把Server端的InputChannel保存了在这个WindowState对象的成员变量mInputChannel中,因此,这里,就可以把它取回来,然后调用mInputManager对象的unregisterInputChannel函数来把它注销掉了。

更多相关文章

  1. Android应用程序键盘(Keyboard)消息处理机制分析(17)
  2. Android Apk反编译函数对应法则
  3. android 根据文件的扩展名选择用什么应用程序打开
  4. android将对象写入文件和从文件中读取对象数据
  5. Android应用程序 启动画面
  6. Android Activity管理类,用于Activity管理和应用程序退出
  7. Android 的一些实用的函数
  8. android中得到所有安装的应用程序及区分其是否为系统应用程序还
  9. 调用其他应用程序的Activity(打电话,浏览网页,发Email)

随机推荐

  1. Android——UI篇:RecyclerView设置点击效
  2. android的map上的浮动菜单以及日历控件
  3. 爱Android更要懂Android
  4. 关于Android NDK中如何调用第三方静态库-
  5. 最牛逼android上的图表库MpChart(三) 条形
  6. android坐标系相关知识点
  7. Android技术人才前途无量
  8. 7GB! | 高焕堂Android从程序员到架构师之
  9. 深入理解Android音频框架AudioTrack到Aud
  10. Android(Java):对应用进行单元测试