文档章节

Activity中KeyEvent的传递

cwr
 cwr
发布于 2015/03/02 23:04
字数 1281
阅读 73
收藏 0
点赞 0
评论 0

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

  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 {
     
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
 
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        Log.d("KEYEVENT", "MainActivity:onKeyDown");
        return super.onKeyDown(keyCode, event);
    }
 
    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        Log.d("KEYEVENT", "MainActivity:onKeyUp");
        return super.onKeyUp(keyCode, event);
    }
 
    @Override
    public void onUserInteraction() {
        Log.d("KEYEVENT", "MainActivity:onUserInteraction");
        super.onUserInteraction();
    }
 
    @Override
    public 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);
    }
 
    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        Log.d("KEYEVENT", "MyFrameLayout:dispatchKeyEvent");
        return super.dispatchKeyEvent(event);
    }
 
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        // TODO Auto-generated method stub
        Log.d("KEYEVENT", "MyFrameLayout:onKeyDown");
        return super.onKeyDown(keyCode, event);
    }
 
    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        // TODO Auto-generated method stub
        Log.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
    }
 
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        Log.d("KEYEVENT", "MyEditText:onKeyDown");
        return super.onKeyDown(keyCode, event);
    }
 
    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        Log.d("KEYEVENT", "MyEditText:onKeyUp");
        return super.onKeyUp(keyCode, event);
    }
 
    @Override
    public 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.MyEditText
        android: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的dispatchKeyEvent
            if (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方法,所以才会有最后一条日志的输出。






© 著作权归作者所有

共有 人打赏支持
cwr

cwr

粉丝 1
博文 8
码字总数 5030
作品 0
扬州
android web view

1、添加权限:AndroidManifest.xml中必须使用许可"android.permission.INTERNET",否则会出Web page not available错误。 2、在要Activity中生成一个WebView组件:WebView webView = new Web...

手绘灿烂
2014/03/13
0
0
android EditText(文本输入框)去掉 系统软件盘的方法

默认状态下,当我们点击文本输入框时,会弹出系统软键盘。 当在大屏幕的android设备上有输入需求时,系统软键盘的已输入文本会感觉字体有些小,不容易看清。本人也未找到方大软键盘输入时文本...

天下杰论
2012/12/13
0
0
android webView使用方法

在开发过程中应该注意几点: 1.AndroidManifest.xml中必须使用许可"android.permission.INTERNET",否则会出Web page not available错误。 2.如果访问的页面中有Javascript,则webview必须设置...

QGlaunch
2015/06/17
0
0
Android webkit keyevent 事件传递过程

前言:基于android webview 上定制自己使用的可移植浏览器apk,遇到好多按键处理的问题。所以索性研究了一下keyevent 事件的传递流程。 frameworks 层 keyevent 事件开始是从/frameworks/bas...

yistn
2015/04/01
0
0
Android webkit 事件传递流程通道分析

前言:基于androidwebview 上定制自己使用的可移植浏览器apk,遇到好多按键处理的问题。所以索性研究了一下keyevent 事件的传递流程。 frameworks层 keyevent事件开始是从/frameworks/base/...

东辉在线
2015/04/01
0
0
Intent中的四个重要属性——Action、Data、Category、Extras

Intent作为联系各Activity之间的纽带,其作用并不仅仅只限于简单的数据传递。通过其自带的属性,其实可以方便的完成很多较为复杂的操作。例如直接调用拨号功能、直接自动调用合适的程序打开不...

亭子happy
2015/02/08
0
1
Intent中的四个重要属性——Action、Data、Category、Extras

原文地址 http://www.cnblogs.com/wisekingokok/archive/2011/08/22/2149847.html   Intent作为联系各Activity之间的纽带,其作用并不仅仅只限于简单的数据传递。通过其自带的属性,其实可...

截图
2014/10/22
0
0
预览文章: android使用webview时按后退退出的问题

使用webview打包美女图片站点http://www.gg4493.cn,代码都好了,具体如下 public class MainActivity extends ActionBarActivity { protected void onCreate(Bundle savedInstanceState) {......

yangjiyue0520
2017/11/02
0
0
笔记KeyEvent 和 TouchEvent在 Activity和View中传递的顺序

由于一个电视机 Key事件传递出现了部分问题,但是五位方向键有时候出现问题 所以使用Activity完全接管了key事件的传递, 自己来控制焦点的变化和五位方向键的按下处理逻辑 在此温习一下key事件...

SuShine
2015/08/27
0
0
android WebView详解

浏览器控件是每个开发环境都具备的,这为马甲神功提供了用武之地,windows的有webbrowser,android和ios都有webview。只是其引擎不同,相对于微软的webbrowser,android及ios的webview的引擎...

amigos_wu
2012/06/25
0
1

没有更多内容

加载失败,请刷新页面

加载更多

下一页

数据库事务的四大特性以及事务的隔离级别

本篇讲述数据库中事务的四大特性(ACID),并且将会详细地说明事务的隔离级别。 如果一个数据库声称支持事务的操作,那么该数据库必须要具备以下四个特性: ⑴ 原子性(Atomicity) 原子性是...

Java大蜗牛
11分钟前
0
0
Spring Boot 整合 MyBatis/通用Mapper/PageHelper分页插件

整合MyBatis 整合通用Mapper 1. POM依赖配置 <properties><mapper.starter.version>2.0.3-beta1</mapper.starter.version></properties><!-- 通用Mapper --><dependency><groupId>t......

OSC_fly
19分钟前
0
0
CentOS7 双网卡绑定

环境 操作系统 CentOS7.5,禁用 NetworkManager 服务 网卡 eth0 网卡 eth1 绑定网卡 bond0 网卡 eth0 配置 修改 /etc/sysconfig/network-scripts/ifcfg-eth0 TYPE=EthernetBOOTPROTO=noneD......

Colben
21分钟前
0
0
zk实战--rpc框架集群化

在看此篇内容时需要浏览下面内容 netty实战--手写rpc框架 前文功能简介以及功能扩充 利用netty来实现一个点对点的rpc调用。客户端和服务端都是靠手写地址进行socket同学的,无法1对多,也无法...

xpbob
37分钟前
11
0
springboot 发送邮件

获取授权码 添加配置 # 账号和密码spring.mail.username=aaa@qq.comspring.mail.password=bbb# 服务器地址spring.mail.host=smtp.qq.comspring.mail.properties.mail.smtp.ssl.en...

阿豪boy
38分钟前
0
0
如何使用GNU Ring?

文章名:如何使用GNU Ring? 作者:冰焰火灵X 1079092922@qq.com 文章许可:CC BY-SA 4.0 ##1. 安装 下载GNU Ring 点击左边选择你的系统版本(这里以 GNU/Linux 为例,我使用的是Mint 18.3)...

ICE冰焰火灵X
41分钟前
4
0
深入理解springMVC

什么是spring MVC Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面。Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。使用 Spring 可插入的 MVC 架构,从而...

Java填坑之路
46分钟前
1
0
《射雕英雄传》书摘

1. 我虽是个飘泊江湖的贫家女子,可不是低三下四、不知自爱之人。你如真心爱我,须当敬我重我。我此生决无别念,就是钢刀架颈,也决意跟定了你。将来……将来如有洞房花烛之日,自然……自能...

k91191
57分钟前
1
0
解决:modal中datePicker 选中时,会触发modal的hidden.bs.modal事件

最近项目中发现了一个bug,具体表现为选中模态框上datepicker组件上的日期时,会触发模态框的关闭事件,导致数据编辑无法正常进行。网上搜索了下,解决方法如下: $('.datepicker').on('hid...

Funcy1122
今天
0
0
Redis分布式锁的正确实现方式

前言 分布式锁一般有三种实现方式: 1.数据库乐观锁 2.基于Redis的分布式锁; 3.基于Zookeeper的分布式锁。本篇博客将介绍第二种方式,基于Redis实现分布式锁。虽然网上已经有各种介绍Redis...

大海201506
今天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部