2019独角兽企业重金招聘Python工程师标准>>>

我们先来写个测试应用,主要文件如下:

  1. MainActivity.java

package com.test.keyevent;import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) {Log.d("KEYEVENT", "MainActivity:onKeyDown");return super.onKeyDown(keyCode, event);}@Overridepublic boolean onKeyUp(int keyCode, KeyEvent event) {Log.d("KEYEVENT", "MainActivity:onKeyUp");return super.onKeyUp(keyCode, event);}@Overridepublic void onUserInteraction() {Log.d("KEYEVENT", "MainActivity:onUserInteraction");super.onUserInteraction();}@Overridepublic boolean dispatchKeyEvent(KeyEvent event) {Log.d("KEYEVENT", "MainActivity:dispatchKeyEvent");return super.dispatchKeyEvent(event);}}

2. MyFrameLayout.java

package com.test.keyevent;import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.widget.FrameLayout;public class MyFrameLayout extends FrameLayout {public MyFrameLayout(Context context) {super(context, null);}public MyFrameLayout(Context context, AttributeSet attrs) {super(context, attrs, 0);}public MyFrameLayout(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);}@Overridepublic boolean dispatchKeyEvent(KeyEvent event) {Log.d("KEYEVENT", "MyFrameLayout:dispatchKeyEvent");return super.dispatchKeyEvent(event);}@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) {// TODO Auto-generated method stubLog.d("KEYEVENT", "MyFrameLayout:onKeyDown");return super.onKeyDown(keyCode, event);}@Overridepublic boolean onKeyUp(int keyCode, KeyEvent event) {// TODO Auto-generated method stubLog.d("KEYEVENT", "MyFrameLayout:onKeyUp");return super.onKeyUp(keyCode, event);}}

3. MyEditText.java

package com.test.keyevent;import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.widget.EditText;public class MyEditText extends EditText {public MyEditText(Context context) {super(context, null);// TODO Auto-generated constructor stub}public MyEditText(Context context, AttributeSet attrs) {super(context, attrs, 0);// TODO Auto-generated constructor stub}public MyEditText(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);// TODO Auto-generated constructor stub}@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) {Log.d("KEYEVENT", "MyEditText:onKeyDown");return super.onKeyDown(keyCode, event);}@Overridepublic boolean onKeyUp(int keyCode, KeyEvent event) {Log.d("KEYEVENT", "MyEditText:onKeyUp");return super.onKeyUp(keyCode, event);}@Overridepublic boolean dispatchKeyEvent(KeyEvent event) {Log.d("KEYEVENT", "MyEditText:dispatchKeyEvent");return super.dispatchKeyEvent(event);}}

4. activity_main.xml

<com.test.keyevent.MyFrameLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@android:color/black"><com.test.keyevent.MyEditTextandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:background="@android:color/white"android:textColor="@android:color/black"android:hint="请输入..." />
</com.test.keyevent.MyFrameLayout>

安装并打开应用。

在adb shell中,输入input keyevent 29 往系统注入一个KeyEvent(29是a的键值,可以在系统源码KeyEvent.java中查到),我们得到如下日志:

03-02 20:18:48.991: D/KEYEVENT(5840): MainActivity:dispatchKeyEvent

03-02 20:18:48.991: D/KEYEVENT(5840): MainActivity:onUserInteraction

03-02 20:18:48.991: D/KEYEVENT(5840): MyFrameLayout:dispatchKeyEvent

03-02 20:18:48.991: D/KEYEVENT(5840): MyEditText:dispatchKeyEvent

03-02 20:18:48.992: D/KEYEVENT(5840): MyEditText:onKeyDown

03-02 20:18:49.040: D/KEYEVENT(5840): MainActivity:dispatchKeyEvent

03-02 20:18:49.040: D/KEYEVENT(5840): MainActivity:onUserInteraction

03-02 20:18:49.040: D/KEYEVENT(5840): MyFrameLayout:dispatchKeyEvent

03-02 20:18:49.040: D/KEYEVENT(5840): MyEditText:dispatchKeyEvent

03-02 20:18:49.040: D/KEYEVENT(5840): MyEditText:onKeyUp

03-02 20:18:49.040: D/KEYEVENT(5840): MainActivity:onKeyUp

下面我们一步一步分析。

1. MainActivity:dispatchKeyEvent

首先被调用的是MainActivity的dispatchKeyEvent的函数。KeyEvent是如何传递到Acitivity中的,这是比较复杂的,可以参看http://blog.csdn.net/luoshengyang/article/details/6882903这篇博文。但要注意,这篇文章是更具android2.3来写的,对于我们常见的4.2以上的系统,经过我分析比较,是有一些不同的。

4.2系统中,native层InputManager不是在windowManagerService中创建的,而是在SystemServer中创建了个InputManagerService,并在里面创建初始化了InputManager。InputManager的启动也是由SystemServer来启动的。并且InputReaderThread的loopOnce()支持一次读取多条event,优化了性能。还有很多其他的不同的地方,但是大体逻辑上还是一样的。

这块好应用开发关系不太大,就不细说了。最终,Activity的ViewRootImpl的deliverKeyEventPostIme方法中会调用       DecorView的dispatchKeyEvent方法,而DecorView的dispatchKeyEvent方法,可以看下源码,它回调了Activity的       dispatchKeyEvent方法,于是,我们看到了这行日志。

2.MainActivity:onUserInteraction

我们看Activity的dispatchKeyEvent方法,

    public boolean dispatchKeyEvent(KeyEvent event) {onUserInteraction();Window win = getWindow();if (win.superDispatchKeyEvent(event)) {return true;}View decor = mDecor;if (decor == null) decor = win.getDecorView();return event.dispatch(this, decor != null? decor.getKeyDispatcherState() : null, this);}

里面调用了onUserInteraction方法。我们可以覆写这个方法,这样就可以在KeyEvent被派发之前,做一些操作,默认是什么都不做。

3. MyFrameLayout:dispatchKeyEvent

从日志看出,事件从Activity又回到了我们的View中。为什么要从Activity中走一下,这样给Activity一个机会,可以控制KeyEvent的派发。

如何回去的,我们接着看Acitivity.dispatchKeyEvent方法

        Window win = getWindow();if (win.superDispatchKeyEvent(event)) {return true;}

win就是Activity的mWindow对象,是一个PhoneWindow。我们看PhoneWindow的superDispatchKeyEvent(KeyEvent event)方法:

    public boolean superDispatchKeyEvent(KeyEvent event) {return mDecor.superDispatchKeyEvent(event);}

mDecor就是我们熟悉的DecorView对象啦,看它的superDispatchKeyEvent:

        public boolean superDispatchKeyEvent(KeyEvent event) {if (super.dispatchKeyEvent(event)) {return true;}......}

因为DecorView是FrameLayout子类,FrameLayout是ViewGroup的子类,所以super.dispatchKeyEvent(event)会调用到ViewGroup的dispatchKeyEvent方法:

  public boolean dispatchKeyEvent(KeyEvent event) {if (mInputEventConsistencyVerifier != null) {mInputEventConsistencyVerifier.onKeyEvent(event, 1);}if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))== (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {// 如果自己有焦点,则调用父类View的dispatchKeyEventif (super.dispatchKeyEvent(event)) {return true;}} else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)== PFLAG_HAS_BOUNDS) {// 子视图有焦点,则调用子视图if (mFocused.dispatchKeyEvent(event)) {return true;}}if (mInputEventConsistencyVerifier != null) {mInputEventConsistencyVerifier.onUnhandledEvent(event, 1);}return false;}

焦点在MyEditText上,而MyEditText包含于MyFrameLayout中,所以最终mFocused.dispatchKeyEvent(event)会调用到MyFrameLayout.dispatchKeyEvent方法。

4. MyEditText:dispatchKeyEvent

MyFrameLayout也是FrameLayout子类,所以MyFrameLayout.dispatchKeyEvent和上面一样,会调用ViewGroup的dispatchKeyEvent。这次mFocused就是MyEditText,调用它的dispatchKeyEvent方法。

5.MyEditText:onKeyDown

MyEditText是View子类,会调用View的dispatchKeyEvent方法:

  public boolean dispatchKeyEvent(KeyEvent event) {......if (event.dispatch(this, mAttachInfo != null? mAttachInfo.mKeyDispatchState : null, this)) {return true;}......return false;}

View.dispatchKeyEvent会调用KeyEvent的dispatch方法:

    public final boolean dispatch(Callback receiver, DispatcherState state,Object target) {switch (mAction) {case ACTION_DOWN: {......boolean res = receiver.onKeyDown(mKeyCode, this);......}}

receiver就是之前的View,也就是MyEditText,也就回调了MyEditText的onKeyDown方法。

至此,ACTION_DOWN的KeyEvent分析完毕。

ACTION_UP的KeyEvent和Down的基本一样,只是应为View的onKeyUp方法返回了false,所以最终会调用到Acitivity的onKeyUp方法,所以才会有最后一条日志的输出。

转载于:https://my.oschina.net/u/262208/blog/381671

Activity中KeyEvent的传递相关推荐

  1. 【Android 事件分发】事件分发源码分析 ( Activity 中各层级的事件传递 | Activity -> PhoneWindow -> DecorView -> ViewGroup )

    Android 事件分发 系列文章目录 [Android 事件分发]事件分发源码分析 ( 驱动层通过中断传递事件 | WindowManagerService 向 View 层传递事件 ) [Andr ...

  2. Android中Activity之间的数据传递(Intent和Bundle)

    当一个Activity启动另一个Activity时,常常会有一些数据传过去,对于Activity之间的数据交换更简单,因为两个Activity之间进行数据传递交换更简单,因为两个Activity之间本 ...

  3. ANDROID中ACTIVITY间的数据传递

    效果:有两个Activity分别为A和B,从A中采用Bundle封装数据向B中传递数据,然后使用startActivityForResult在B中修改后回传数据. 第一个Activity的layout ...

  4. 【转】android之在activity中控制另一个activity的UI更新_如何在activity之间传递handler...

    来自:http://blog.csdn.net/jason0539/article/details/18055259 遇到一个问题,需要在一个activity中控制另一个acitivity做一些更新, ...

  5. Android 中activity中传递数据的方式

    方式一 通过Intent进行数据传递(日后更新) 方式二 通过剪切板进行数据的传递 首先在第一个Activity中,设置所要进行传递的数据 /*** 通过剪贴板传递字符串数据的操作**/private ...

  6. Android中的两个Activity用Intent来传递java bean实体

    先定义java bean实体: public class MC_bean implements Serializable {private int code;private String messag ...

  7. 点击事件如何传递到Activity中

    1.首先,当我们触摸屏幕时,通过Android消息机制,从Looper从MessageQueue中取出该事件,发送给WindowInputEventReceiver. 2.WindowInputEve ...

  8. android自定义view获取控件,android 自定义控件View在Activity中使用findByViewId得到结果为null...

    转载:http://blog.csdn.net/xiabing082/article/details/48781489 1.  大家常常自定义view,,然后在xml 中添加该view 组件..如果在 ...

  9. Android中事件的传递

    Android中事件的传递 首先来张图看看    1. 核心方法返回值的含义 dispatchTrackballEvent 分发事件 public boolean dispatchTrackballE ...

最新文章

  1. 致被套基民:老基民的四点教训七点经验(ZT)
  2. Windows下编辑的(脚本)文本copy到linux下带个^M结尾
  3. 概念模型让产品更简单
  4. 01-MyBatis入门程序
  5. javafx响应式布局_JavaFX的响应式设计
  6. 如何获取url中的参数并传递给iframe中的报表
  7. mysql安装数据自定义_mysql数据库自定义怎么安装
  8. 云小课 | IPv4枯了,IPv6来了
  9. Maven 国内镜像
  10. Datagrid,DataList,Repeate等的数据格式设置表达式
  11. 大数据存储峰会4月9日深圳开幕
  12. Springboot启动报错:Failed to process import candidates for configuration class...
  13. JavaScript 计算标准体重的公式
  14. U3D常用介绍,搭建一个简单的三维效果
  15. 1038: 绝对值最大
  16. SEO基础知识简介(一)
  17. 使用VS2012进行单元测试
  18. 11家共享单车可通过支付宝免押骑车,这种省钱的方法你get了吗?
  19. 跟随小米等手机厂商的 IoT 步伐,OPPO 推出子品牌“智美心品”
  20. Fiddler 抓包工具总结(转)

热门文章

  1. SAP LSMW 导入Open PO时价格不对问题之对策
  2. 联邦学习怎样应用在推荐系统中?
  3. 美国没有光刻机背后的原因
  4. 重磅盘点:过去8年中深度学习最重要的想法
  5. 能源枯竭?在能源互联网时代不存在!
  6. “脑补”的科学依据:眼前的黑不是黑,靠得是你的大脑
  7. 工信部:筹建全国首个区块链和分布式记账标准化技术委员会
  8. 这几家公司有个梦想:开发AI操作系统,让外行也成为人工智能大师
  9. 重回大厂 996 的年轻人:还是先搞钱
  10. 去年我年薪 30W,今年我一天做 3 顿饭