android升级到AppCompat v22.1.0后,onKeyDown 和 onKeyUp menu按键不能被触发的解决办法

来源:互联网 发布:php ruby perl python 编辑:程序博客网 时间:2024/05/18 18:52

今天在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
0 0
原创粉丝点击