当按下菜单键时,不会触发升级到AppCompat v22.1.0以及现在的onKeyDown和onKeyUp

我刚刚升级了我的应用程序以使用新发布的v22.1.0 AppCompat,现在onKeyDown和按下菜单键时不会触发onKeyUp 。 其他键正确触发onKeyDownonKeyUp ,但是当我按下菜单键时没有任何反应。 如果我降级到v22.0.0,一切都恢复正常。

我如何解决它?

    8月23日更新

    这已在appcompat-v7支持库的v23.0.0中再次修复 。 更新到上一个版本以查看此修复。


    7月19日更新

    不幸的是,AppCompat v22.2.1 再次破坏了onKeyDownonKeyUp事件。 我刚刚更新了AppCompatActivityMenuKeyInterceptor以支持v22.1.x和v22.2.1


    5月29日更新

    这已在appcompat-v7支持库的v22.2.0中修复。 更新到上一个版本以查看此修复。


    不幸的是,AppCompat v22.1.0拦截onKeyDownonKeyUp事件,并且在按下菜单键时不会传播它们。 唯一可能的解决方案是在AppCompat之前使用Reflection来拦截onKeyDownonKeyUp事件。

    将此类添加到项目中:

     public class AppCompatActivityMenuKeyInterceptor { private static final String FIELD_NAME_DELEGATE = "mDelegate"; private static final String FIELD_NAME_WINDOW = "mWindow"; public static void intercept(AppCompatActivity appCompatActivity) { new AppCompatActivityMenuKeyInterceptor(appCompatActivity); } private AppCompatActivityMenuKeyInterceptor(AppCompatActivity activity) { try { Field mDelegateField = AppCompatActivity.class.getDeclaredField(FIELD_NAME_DELEGATE); mDelegateField.setAccessible(true); Object mDelegate = mDelegateField.get(activity); Class mDelegateClass = mDelegate.getClass().getSuperclass(); Field mWindowField = null; while (mDelegateClass != null) { try { mWindowField = mDelegateClass.getDeclaredField(FIELD_NAME_WINDOW); break; } catch (NoSuchFieldException ignored) { } mDelegateClass = mDelegateClass.getSuperclass(); } if (mWindowField == null) throw new NoSuchFieldException(FIELD_NAME_WINDOW); mWindowField.setAccessible(true); Window mWindow = (Window) mWindowField.get(mDelegate); Window.Callback mOriginalWindowCallback = mWindow.getCallback(); mWindow.setCallback(new AppCompatWindowCallbackCustom(mOriginalWindowCallback, activity)); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } private class AppCompatWindowCallbackCustom extends WindowCallbackWrapper { private WeakReference mActivityWeak; public AppCompatWindowCallbackCustom(Window.Callback wrapped, AppCompatActivity appCompatActivity) { super(wrapped); mActivityWeak = new WeakReference(appCompatActivity); } @Override public boolean dispatchKeyEvent(KeyEvent event) { final int keyCode = event.getKeyCode(); AppCompatActivity appCompatActivity = mActivityWeak.get(); if (appCompatActivity != null && keyCode == KeyEvent.KEYCODE_MENU) { if (appCompatActivity.dispatchKeyEvent(event)) return true; } return super.dispatchKeyEvent(event); } } } 

    在活动的onCreate中调用AppCompatActivityMenuKeyInterceptor.intercept(this)

     public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //Initialize the interceptor AppCompatActivityMenuKeyInterceptor.intercept(this); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { // Now onKeyDown is called also for KEYCODE_MENU if (keyCode == KeyEvent.KEYCODE_MENU) { //do your stuff //return false if you want to propagate the //KeyEvent to AppCompat, return true otherwise return false; } return super.onKeyDown(keyCode, event); } @Override public boolean onKeyUp(int keyCode, KeyEvent event) { // Now onKeyUp is called also for KEYCODE_MENU if (keyCode == KeyEvent.KEYCODE_MENU) { //do your stuff //return false if you want to propagate the //KeyEvent to AppCompat, return true otherwise return false; } return super.onKeyUp(keyCode, event); } } 

    如果您使用ProGuard或DexGuard,请将这些规则添加到您的配置中:

     -keepclassmembers class android.support.v7.app.AppCompatActivity { private android.support.v7.app.AppCompatDelegate mDelegate; } -keepclassmembers class android.support.v7.app.AppCompatDelegateImplBase { final android.view.Window mWindow; } 

    现在,您的活动也可以为菜单键接收onKeyDownonKeyUp事件。

    可以简单地使用dispatchKeyEvent()代替onKeyUp()onKeyDown() dispatchKeyEvent() 。 请查看android-developers.blogspot.com中的以下代码。

     @Override public boolean dispatchKeyEvent(KeyEvent event) { if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) { if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) { // Tell the framework to start tracking this event. getKeyDispatcherState().startTracking(event, this); return true; } else if (event.getAction() == KeyEvent.ACTION_UP) { getKeyDispatcherState().handleUpEvent(event); if (event.isTracking() && !event.isCanceled()) { // DO BACK ACTION HERE return true; } } return super.dispatchKeyEvent(event); } else { return super.dispatchKeyEvent(event); } }