keyevent 系统

  关于android系统如何从底层读取事件,就不描述了,本人也不懂,因为是c++写的,我们只要知道在java层有一个 InputHandler和Kqueue等待输入,或者读取从底层传

上来的数据,本文描述的是从InputHandler收到输入key开始。
  
     文章说明
                                   1. WMS代表WindonManagerService类
                                  2.文章中的流程数字描述和流程图中的对应

     总的流程图如小:
    
      
   
   流程图详解:
       
  • android系统启动时,启动输入监听程序
  • WMS监听到输入事件
  • WMS判断是否为系统事件,比如home键之类的,如果是系统键,则WMS就处理了,所以我们应用程序没法获取到home
  • WMS判断是系统键,直接消费,事件结束
  • WMS判断是系统键,直接消费,事件结束
  • WMS交给ViewRootImpl,ViewRootImpl中的InputHandler读取到key事件后,deliverKeyEvent开始处理
  • 首先调用mView.dispatchKeyEventPreIme(event),这个方法作用就是当输入法显示的时候,在处理输入法前处理一些东西,程序员可以重写。其中mView对应的是PhoneWindow的DecorView,DecorView继承自FrameLayout,他们都没有重写dispatchKeyEventPreIme方法,所以最后调用ViewGroup的dispatchKeyEventPreIme。在ViewGroup中的默认处理有两种  :1.如果view自己有焦点,则调用super.dispatchKeyEventPreIme(event),即调用view的默认处理逻辑,view默认的处理逻辑是调用了onKeyPreIme方法,而onKeyPreIme直接返回false。在应用中,我们重写view时,可以重写该方法,如果onKeyPreIme方法返回为true,则本次事件结束。2:如果view自己没有焦点,看view的mfocueed是否为null,且该mfocused是否有焦点,如果有焦点调用mFocused.dispatchKeyEventPreIme(event)方法,然后就和第一种情况处理逻辑一样。
  • 如果7中没有消费消息,则判断输入法窗口是否显示,如果显示则将事件交给IME处理
  • 如果8中没有消费消息,则交给mView.dispatchKeyEvent(event),mview对象是:PhoneWindon.DecorView,如果没有处理消息,则处理20
  • 在mView.dispatchKeyEvent(event)中,判断getCallback()是否为空,一般情况下,如果为空说明不是Activity窗口,如果为空则调用super.dispatchKeyEvent(event),即进入view树处理逻辑,请移步至23中。如果getCallBack()不为空,说明是Activity对象,因为Activity继承了Windon.CallBack接口,然后调用ActivitydispatchKeyEvent(event)方法,如果没有处理,则调用PhoneWindow的onkeydown和onkeyUP方法,没有对于的流程图
  • 不好意思11画图给漏掉了

  • Activity的dispatchkeyEvent中首先调用 onUserInteraction();程序可以重写该方法,表示在处理之前先做点什么,
  • 然后调用win.superDispatchKeyEvent(event),win对应的类是PhoneWindow,如果win.superDispatchKeyEvent(event)返回的是true,则处理结束,如果是false,则调用event.dispatch方法,在该方法出会调用Activity的onkeyDwon和onKeyup方法,这些对于在17,
  • PhoneWindow的superDispatchKeyEvent直接调用mDecor.superDispatchKeyEvent(event),mDecor对于的类是PhoneWindow.DecorView,如果返回false,则返回给13,
  • mDecor.superDispatchKeyEvent(event)直接调用super.dispatchKeyEvent(event),即直接调用ViewGroup的dispatch,如果viewGroup的dispatch返回的是false,返回给14
  • 进入view树处理逻辑,请查看24
  • 如果返回的是false,则交给15
  • 这个如果Activity中包含的所有View都没有消费该消息,则在调用Event.dispatch方法
  • 调用Activity的Onkeydown和onkeyup方法
  • 如果应用的窗口都没有消费该消息,那么方法事件派送有回到了ViewRootImpt中了,其实ViewRootImlp就会根据上下左右来做焦点变化了
  • 如果没有发现焦点变化,那么事件就结束了
  • 结束事件
  • 这个是关于view树中的onkey处理逻辑,本来些东西应该在20-22前,但是为跟方便体现事件在整个Activity过程的流程,所以将事件在view树中的处理逻辑放在后边了,
  • 进入View树,View树,即我们在布局中写的view层级关系,比如ViewGroup---Viewgroup---ViewGroup-Button,一层一层包含,进入view树的接口是Viewgroup(也有可能是view)的dispatchKeyEvent方法,首先判断ViewGroup自己是否有焦点.进入这里的入口有三个:分别是16和10,30
  • 如果有,则调用super.dispatchKeyEvent(event)方法,即view的方法dispatchKeyEvent(event)
  • view的dispatchKeyEvent(event)方法,首先调用OnKeyListener的onkey方法,即我们通过setOnKeyListener设置的方法,
  • 如果onkey没有消费则调用event.dispatch方法
  • 调用view的onkeydown和onkeyup,如果还是没有消费了,则返回false给10或者16或者30的调用处
  • 如果24中判断没有焦点,则查看mFocused是否为空,mfouces代表的是viewGroup中的有焦点的子View对象(可能是view也可能是ViewGroup),关于mfocused表示的对象,举例说一下:比如有个布局是 A包含B,B包含C,C是view对象(具体的view,不是继承自viewGroup的),而此时C是有焦点的,那么A的mFocused对象是B,B的是C,一层一层往下走
  • 如果mFoucsed存在,在调用mFocused.dispatchKeyEvent(event),这里再次进入24的逻辑中,即view树处理
  • 如果24view树的消费了消息,则结束一层一层返回
  • 如果没有处理,则调用evnet.dispatch,调用onkeydown和onkeyup,如果没有消费消息,则一层一层完会,返回给调用者,
  • 如果所有的东西都没有消费,最后交给20。


大概流程就这样,总结一下:


       1.onkey事件在WMS层会有一个过滤,将系统key给过滤掉,而ontounch事件是没有的,直接交给了应用
        2.从VIewRootImpl一层一层往上派送事件,如果没有处理,则一层一层返回,每次都有自己的onkeydown事件和onkeyup事件的调用
       3.整个事件派送流程(不考虑IME) :WMS----->ViewRootImpl----->DecorView----->Activity----->PhoneWindon----DecorView(这里派送没有调用dispatchKeyEvent方法,因为已经调用一次,调用的是superDispatchKeyEvent方法)----->ViewGroup(肯能存在多层)----->View
       4.返回过程:调用view的onkeyListener没有消费,onkeydown和onkeyup没有消费------->调用ViewGroup(可能存在多层)onkeyListener没有消费,onkeydown和onkeyup没有消费  ---->Activity的onkeydown和onkeyup没有消费没有消费-------->PhoneWindow的onkeydown和onkeyup没有消费---->ViewRootImpl焦点变化--->事件消失
       5.事件传递过程中,都是先diapatch,然后在disaptch没有消费后,才调用自己的onkeyDown和onKeyup


以上就是android的onkey事件大概派送流程,今天就到这里把,

如有问题,请多多指教

你可能感兴趣的:(android基础,高级,源码开发,游戏开发。。。。)