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

  • Post author:
  • Post category:其他





今天在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




版权声明:本文为xuejinwei0530原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。