今天在android studio下做重写onKeyDown修改menu按键功能的时候,发现代码没有问题,就是在点击menu按键的时候onKeyDown不能被触发,代码如下:
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
Log.i("Err", keyCode + event.toString());
<span style="white-space:pre"> </span>
if (keyCode == KeyEvent.KEYCODE_MENU) {
Toast.makeText(this, keyCode + event.toString(), Toast.LENGTH_SHORT).show();
return true;
} else {
return super.onKeyDown(keyCode, event);
}
}
此时依次按下 音量+,-,menu,back……按键的时候,其他按键都能被相应,都能够在logcat显示出日志,唯独menu按键不被监听,日志如下图
排除代码问题之后,大概认定是sdk的问题,经过google查询,在stackoverflow找到相同的问题以及解决方法,原文链接如下:http://stackoverflow.com/questions/29852303/upgraded-to-appcompat-v22-1-0-and-now-onkeydown-and-onkeyup-are-not-triggered-wh/29852304#
原文给出的解决方案解释是这样的,升级AppCompat v22.1.0之后,onKeyDown and onKeyUp方法中按下menu时候事件不被传播,唯一的解决方法是,在
AppCompat 执行menu事件之前利用反射拦截onKeyDown和onKeyUp的事件,翻译的不准,见效了。
解决方法:
1.在自己项目添加如下类:
<span style="font-size:18px;">import android.support.v7.app.AppCompatActivity;
import android.support.v7.internal.view.WindowCallbackWrapper;
import android.view.KeyEvent;
import android.view.Window;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
/**
* Created by M星空 on 2015/5/7 0007.
*/
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);
Field mWindowField = mDelegate.getClass().getSuperclass().getSuperclass().getDeclaredField(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<AppCompatActivity> mActivityWeak;
public AppCompatWindowCallbackCustom(Window.Callback wrapped, AppCompatActivity appCompatActivity) {
super(wrapped);
mActivityWeak = new WeakReference<AppCompatActivity>(appCompatActivity);
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
final int keyCode = event.getKeyCode();
final int action = event.getAction();
AppCompatActivity appCompatActivity = mActivityWeak.get();
if (appCompatActivity != null) {
if (keyCode == KeyEvent.KEYCODE_MENU && action == KeyEvent.ACTION_DOWN) {
if (mActivityWeak.get().onKeyDown(event.getKeyCode(), event))
return true;
} else if (keyCode == KeyEvent.KEYCODE_MENU && action == KeyEvent.ACTION_UP) {
if (mActivityWeak.get().onKeyUp(event.getKeyCode(), event))
return true;
}
}
return super.dispatchKeyEvent(event);
}
}
}</span>
2.在activity的onCreate方法中添加如下代码:
AppCompatActivityMenuKeyInterceptor.intercept(this);
整个activity代码如下:
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
AppCompatActivityMenuKeyInterceptor.intercept(this);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
Log.i("Err", keyCode + event.toString());
if (keyCode == KeyEvent.KEYCODE_MENU) {
Toast.makeText(this, keyCode + event.toString(), Toast.LENGTH_SHORT).show();
return true;
} else {
return super.onKeyDown(keyCode, event);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
至此,就解决了AppCompat v22.1.0 新版本onKeyDown 或者 onKeyUp menu事件不能够被传出的问题,但是这里遇到另外一个问题,如果activity有actionbar有三个点需要显示的menu的话,点击menu按键的时候,除了,会执行onKeyDown自定义的功能外,还会执行弹出actionbar菜单的功能,如下:
menu属性showAsAction=”always”就行了,就是不要显示三个点的按钮在actionbar