ViewGroup类的成员函数dispatchKeyEventPreIme首先是检查当前正在处理的视图容器是否能够获得焦点。如果能够获得焦点的话,那么ViewGroup类的成员变量mPrivateFlags的FOCUSED位会等于1。在当前正在处理的视图容器能够获得焦点的情况下,还要检查正在处理的视图容器是否已经计算过大小了,即检查ViewGroup类的成员变量mPrivateFlags的HAS_BOUNDS位是否等于1。只有在已经计算过大小并且能够获得焦点的情况下,那么正在处理的视图容器才有资格处理参数event所描述的键盘事件。注意,正在处理的视图容器是通过调用其父类View的成员函数dispatchKeyEventPreIme来处理参数event所描述的键盘事件的。

  如果当前正在处理的视图容器没有资格处理参数event所描述的键盘事件,但是它有一个能够获得焦点的子视图,并且这个子视图的大小也是已经计算好了的,那么ViewGroup类的成员函数dispatchKeyEventPreIme会将参数event所描述的键盘事件分发给该子视图处理。当前正在处理的视图容器能够获得焦点的子视图是通过ViewGroup类的成员变量mFocused来描述的,通过调用这个成员变量所描述的一个View对象的成员函数dispatchKeyEventPreIme即可将参数event所描述的键盘事件分发给够获得焦点的子视图处理。

  一个视图容器是如何知道它的焦点子视图的呢?我们知道,当我们在屏幕上触摸一个窗口时,会发生一个Pointer事件。这个Pointer事件关联有一个触摸点,通过检查这个触摸点当前是包含在窗口顶层视图的哪一个子视图里面,可以知道哪一个子视图是焦点子视图了。

  从上面的分析可以知道,无论是当前正在处理的视图容器获得焦点,还是它的子视图获得焦点,终都是通过调用View类的成员函数dispatchKeyEventPreIme来在输入法之前处理参数event所描述的键盘事件,因此,接下来我们继续分析View类的成员函数dispatchKeyEventPreIme的实现。

  Step 3. View.dispatchKeyEventPreIme

  [java] view plaincopyprint?

  public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource {

  ......

  public boolean dispatchKeyEventPreIme(KeyEvent event) {

  return onKeyPreIme(event.getKeyCode(), event);

  }

  ......

  }

  public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource {

  ......

  public boolean dispatchKeyEventPreIme(KeyEvent event) {

  return onKeyPreIme(event.getKeyCode(), event);

  }

  ......

  }

  这个函数定义在文件frameworks/base/core/java/android/view/View.java中。

  View类的成员函数dispatchKeyEventPreIme的实现很简单,它只是通过调用另外一个成员函数onKeyPreIme来在输入法之前处理参数event所描述的键盘事件。

  Step 4. View.onKeyPreIme

  [java] view plaincopyprint?

  public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource {

  ......

  public boolean onKeyPreIme(int keyCode, KeyEvent event) {

  return false;

  }

  ......

  }

  public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource {

  ......

  public boolean onKeyPreIme(int keyCode, KeyEvent event) {

  return false;

  }

  ......

  }

  这个函数定义在文件frameworks/base/core/java/android/view/View.java中。

  View类的成员函数onKeyPreIme默认是不会在输入法之前处理参数event所描述的键盘事件的,因此,我们在实现自己的控件的时候,如果需要在输入法之前处理键盘输入,那么必须重写父类View的成员函数onKeyPreIme。在重写父类View的成员函数onKeyPreIme来处理一个键盘事件的时候,如果不希望这个键盘事件分发给输入法处理,那么返回一个true值,否则的话,返回一个false值。

  我们假设当前获得焦点的是图1所示的TextView控件,但是由于TextView类没有重写其父类View的成员函数onKeyPreIme,因此,参数event所描述的键盘事件接下来会继续分发给输入法或者当前激活的窗口处理。

  这一步执行完成之后,回到前面的Step 1中,即ViewRoot类的成员函数deliverKeyEvent中,无论接下来是否需要先将一个键盘事件分发给输入法处理,终都会调用到ViewRoot类的成员函数deliverKeyEventToViewHierarchy来继续将该键盘事件分发给当前激活的窗口处理。