在公司实际TV项目开发apk过程中,Activity的 dispatchKeyEvent
、onKeyDown
响应遥控器按键弹出对话框(DialogFragment、Dialog、AlertDialog)时,出现概率性无法响应到遥控器按键的问题(除Home按键),打印日志大致如下:
ViewRootImpl(27708): Dropping event due to no window focus: KeyEvent { action=ACTION_DOWN, keyCode=KEYCODE_BACK, scanCode=0, metaState=0, flags=0x8, repeatCount=0, eventTime=24289753, downTime=24289753, deviceId=-1, source=0x101 }
按键响应:
@Override
public boolean dispatchKeyEvent(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN/ACTION_UP) {
// showDialog()
return true;
}
}
或者
@Override
public boolean onKeyDown(int keyCode) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
// showDialog
return true;
}
}
目前找到的解决方案是重写Activity的 onKeyUp
,不使用 dispatchKeyEvent
或 onKeyDown
响应弹出对话框(其他按键响应可以正常使用 dispatchKeyEvent
或 onKeyDown
):
@Override
public boolean onKeyUp(int keyCode) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
// showDialog()
return true;
}
}
两个注意点:
1、跳转Activity有响应相同的按键可能会出现冲突,比如从Activity A跳转到 Activity B,跳转界面响应的是按键 KeyEvent.KEYCODE_0
,而Activity B的 onKeyUp
也有拦截该按键,出现的现象是Activity B的 onKeyUp
被响应了,这里只使用一个标志位延时判断:
public ActivityA extends AppCompatActivity {
@Override
public boolean onKeyUp(int keyCode) {
if (keyCode == KeyEvent.KEYCODE_0) {
startActivity(new Intent(this, ActivityB.class);
return true;
}
}
}
public ActivityB extends AppCompatActivity {
private boolean keyUpReady;
@Override
public void onResume() {
super.onResume();
Log.i(TAG, "onResume");
new Handler().postDelay(new Runnable() {
keyUpReady = true;
}, 300);
}
@Override
public boolean onKeyUp(int keyCode) {
if (!keyUpReady) return super.onKeyUp(keyCode);
if (keyCode == KeyEvent.KEYCODE_0) {
Log.i(TAG, "onKeyUp");
// ...
return true;
}
}
}
日志打印:
onResume
onKeyUp
2、弹出的对话框内部响应拦截的按键统一是按下事件 KeyEvent.ACTION_DOWN
不能使用 KeyEvent.ACTION_UP
,防止与Activity的 onKeyUp
按键起冲突。