转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52835829

前言:上篇中,《Android TV开发总结(二)构建一个TV Metro界面(仿泰捷视频TV版)》对应的源码解析见《TV Metro界面(仿泰捷视频TV版)源码解析》一文,链接:http://blog.csdn.net/hejjunlin/article/details/52822499,github对应地址:https://github.com/hejunlin2013/TVSample,截至到当前发稿,已突破200star,如果喜欢的话,可以star,也表示下支持,今天主要总结下TV开发中有焦点问题。

在TV开发中没有以前我们phone端的dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent 事件来分发,而需要使用dispatchKeyEvent、onKeyDown、onKeyLisenter 等事件来分发处理焦点事件传递,而且TV端焦点没有什么好办法可以全局控制,需要我们自己来想办法规定焦点走向,可以参考我的View焦点总结《Android View框架总结(二)View焦点》,本篇做应用场景补充说明及遇到有坑,看下Agenda:

  • 采用Android自带的直接控制焦点上下左右
  • 采用setOnFocusChangeListener控制焦点
  • adb按键派发控制焦点
  • 遇到的坑-遥控器按键失灵案列

Android TV 开发与一般Android开发最大的区别在于焦点控制 , 用户在使用Android TV设备主要是通过遥控器操作app。焦点就是让用户知道的直接交互行为。 然而一些app,依据系统对focus的判断,会出现的状况: 上下导航时,不是想要的结果. 边缘移动时,会出现焦点丢失的状况. 有时想直接定位到某个位置上.
android提供了一些焦点相关的属性,在现有的框架层下通过设置View的属性来获得焦点




下面列出三种方法处理焦点问题

一、采用Android自带的直接控制焦点上下左右的方法

采用Android自带的直接控制焦点上下左右的方法

因此在进行布局时有必须要通过view.setId(…)指定view的特定ID,然后通过view.setNextLeftView(…)等四个方法控制该view的上下左右移动后所到达的view。然而这种方法只适用于前提就设置好ID的场景,不适合动态布局的场景。

看如下一段布局:




rg_a1,rg_a2,rg_a3,rg_a4实际业务中会写明其含义,而不是a1,a2之类,这里只是为介绍,这个自定义的MyCustomButton,按遥控器左键时,将找id为rg_a1的view,焦点跳过去,按遥控器右键时,将找id为rg_a2的view,焦点跳过去,按遥控器下键时,将找id为rg_a3的view,焦点跳过去,按遥控器上键时,将找id为rg_a5的view,焦点跳过去。

二、采用setOnFocusChangeListener控制焦点

看如下一段代码:




当OnFocusChangeListener时,就是从一个焦点跳到另一个view上的变化过程。

三、adb按键派发控制焦点

按键的派发须了解一此KeyCode,下面是平时用到的主要的一些方向键:




在按键过程中 按下和松开的Action主要是ACTION_DOWN、ACTION_UP事件分发和处理是在ACTION_DOWN中处理

当设置View.setFocusable(true); 改变控件是否可以获得焦点,然而同时会触发 setOnFocusChangeListener事件

在adb中,可以通过注入的方式模拟按键,如 adb shell input keyevent 3 给示模拟Home键
以下是的KEYCODE供参考:

KEYCODE_UNKNOWN=0;KEYCODE_SOFT_LEFT=1;KEYCODE_SOFT_RIGHT=2;KEYCODE_HOME=3;KEYCODE_BACK=4;KEYCODE_CALL=5;KEYCODE_ENDCALL=6;KEYCODE_0=7;KEYCODE_1=8;KEYCODE_2=9;KEYCODE_3=10;KEYCODE_4=11;KEYCODE_5=12;KEYCODE_6=13;KEYCODE_7=14;KEYCODE_8=15;KEYCODE_9=16;KEYCODE_STAR=17;KEYCODE_POUND=18;KEYCODE_DPAD_UP=19;KEYCODE_DPAD_DOWN=20;KEYCODE_DPAD_LEFT=21;KEYCODE_DPAD_RIGHT=22;KEYCODE_DPAD_CENTER=23;KEYCODE_VOLUME_UP=24;KEYCODE_VOLUME_DOWN=25;KEYCODE_POWER=26;KEYCODE_CAMERA=27;KEYCODE_CLEAR=28;KEYCODE_A=29;KEYCODE_B=30;KEYCODE_C=31;KEYCODE_D=32;KEYCODE_E=33;KEYCODE_F=34;KEYCODE_G=35;KEYCODE_H=36;KEYCODE_I=37;KEYCODE_J=38;KEYCODE_K=39;KEYCODE_L=40;KEYCODE_M=41;KEYCODE_N=42;KEYCODE_O=43;KEYCODE_P=44;KEYCODE_Q=45;KEYCODE_R=46;KEYCODE_S=47;KEYCODE_T=48;KEYCODE_U=49;KEYCODE_V=50;KEYCODE_W=51;KEYCODE_X=52;KEYCODE_Y=53;KEYCODE_Z=54;KEYCODE_COMMA=55;KEYCODE_PERIOD=56;KEYCODE_ALT_LEFT=57;KEYCODE_ALT_RIGHT=58;KEYCODE_SHIFT_LEFT=59;KEYCODE_SHIFT_RIGHT=60;KEYCODE_TAB=61;KEYCODE_SPACE=62;KEYCODE_SYM=63;KEYCODE_EXPLORER=64;KEYCODE_ENVELOPE=65;KEYCODE_ENTER=66;KEYCODE_DEL=67;KEYCODE_GRAVE=68;KEYCODE_MINUS=69;KEYCODE_EQUALS=70;KEYCODE_LEFT_BRACKET=71;KEYCODE_RIGHT_BRACKET=72;KEYCODE_BACKSLASH=73;KEYCODE_SEMICOLON=74;KEYCODE_APOSTROPHE=75;KEYCODE_SLASH=76;KEYCODE_AT=77;KEYCODE_NUM=78;KEYCODE_HEADSETHOOK=79;KEYCODE_FOCUS=80;//*Camera*focusKEYCODE_PLUS=81;KEYCODE_MENU=82;KEYCODE_NOTIFICATION=83;KEYCODE_SEARCH=84;KEYCODE_MEDIA_PLAY_PAUSE=85;KEYCODE_MEDIA_STOP=86;KEYCODE_MEDIA_NEXT=87;KEYCODE_MEDIA_PREVIOUS=88;KEYCODE_MEDIA_REWIND=89;KEYCODE_MEDIA_FAST_FORWARD=90;KEYCODE_MUTE=91;



  • 问题描述:播放中出现屏保,从屏保回到某页面后,遥控器失灵。从某页进入全屏播放,暂停,等小米的屏保出来后将屏保消失,返回到某页面继续播放。此时遥控器方向键、确定键均无响应。Home键、电源键有响应。菜单键有响应。
    分析:没有响应,按键被拦截,查了下当时改动的代码时,对按键并未做特殊拦截…. 对比之前的版本,没有这个问题。确认问题出现在浮层…从log中看,onWindowFocusChanged,在从h5界面/屏保界面回到某页面,没有被调用。
    说明从window到activity这层,按键就被吃掉了。



  • 接着分析:整个BaseActivity,没有接收到Action_Down事件
    Log中打印的“Dropping event due to no window focus”,思路又断了。
    继续做对比,发现show出浮层时,没有任何异常,但是只要show时,焦点移动,就能复现按键不响应。最后就定位到一个自定义控件上



  • 再接着分析:这个控件1600多行代码,最初一直在找之前版本改动的地方区别,之前版本主要是做一些对这个控件的定制化,其他的先不考虑,排除法,找和event相关的方法。dispatchKeyEvent没有任何异常,又没有思路了,既然是系统级别的传递过程中就被吃了,会不会和view相关,因为只要焦点移动,就失灵,焦点移动伴随着,有一个popupwindow弹出,最终定位在onAttachWindow,好像也没有做什么特殊的事,用了一个getHandler,起初我以为是个自己写的方法,追点进去getHandler一看,是View的


  • 问题修复:
    总结:用View的Handler以前是为处理popupwindow时,popupwindow通过post的方式去show,但是如果此时activity ondestory则会导致出错,所以加了onDetachWindow和onAttachWindow,原因主要是在onDetachWindow时,mHandler.removeCallbacksAndMessages(null);这句话导致,它相当于是把window发给View这层message给移除了。最后修改只移除它对应的的runnable,问题修复。


第一时间获得博客更新提醒,以及更多android干货,源码分析,欢迎关注我的微信公众号,扫一扫下方二维码或者长按识别二维码,即可关注。




如果你觉得好,随手点赞,也是对笔者的肯定,也可以分享此公众号给你更多的人,原创不易

更多相关文章

  1. Android(安卓)EditText得到和失去焦点时,自定义处理内容
  2. Android(安卓)View如何获取焦点
  3. Android输入系统(三):加载按键映射
  4. Android关机充电流程
  5. android 4.4 按键分析三
  6. android – 页面初始化时让组件得不到焦点
  7. 9.9、Libgdx之软键盘
  8. Android(安卓)ApiDemos示例解析(150):Views->Layouts->LinearLay
  9. Android(安卓)Studio--android:descendantFocusability用法简析

随机推荐

  1. 陈丹琦博士论文翻译:神经阅读理解与超越(Ne
  2. 落地三年,两次架构升级,网易的Service Mesh
  3. 机器学习对计量经济学的影响, AEA年会独
  4. 内生变量的交互项如何寻工具变量, 交互项
  5. 无代码开发,站到了程序员鄙视链顶端
  6. 3-31(string底层实现)
  7. Prometheus 之 K8S系统组件服务监控
  8. 2019.1.1, see you again
  9. 听说你还没读过 Bert 源码?
  10. 易错:函数方式实现二分查找整形数组