ハードキーフックの方法
フックしたいんだ
今作っているアプリでBACKキーのフックをしたかったので、以下のようなコードを書きました。
@Override public boolean onKeyUp(int keyCode, KeyEvent event){ if(keyCode == KeyEvent.KEYCODE_BACK) { foo(); return true; } return false; }
しかしこれでは思ったように機能してくれません。
先にKeyDownで本来のBACKキーの機能が働き、Activityが閉じてしまいます。
onKeyDownをオーバーライドすればうまくいきそうなので、書き直します。
@Override public boolean onKeyDown(int keyCode, KeyEvent event){ if(keyCode == KeyEvent.KEYCODE_BACK) { foo(); return true; } return false; }
これでBACKキーのフックができました。
HT-03Aで動かしてみても、正常に動作することが確認できます。
しかし
この実装をしたときに、何気なくツイートしたところ、
@adamrockerさんにdispatchKeyEventの方がいいよとアドバイスされました。
たしかにHT-03A(1.6)ではonKeyDownにBACKキーがアサインされていたけど、
他の端末ではその保障はありません。
実は他の端末ではonKeyUpにアサインされていて、残念なことになることもありえます。
dispatchKeyEventならKeyDownのときも、KeyUpのときも呼ばれるので、安心ですね。
せっかくなんで
すでにバージョンによって動きが違う部分があるのかどうか、調べてみました。
ソース読みます。
Activityクラスのソースコード Activity.java - core/java/android/app - Code Search: http://www.google.co.jp/codesearch/p?hl=ja#uX1GffpyOZk/core/java/android/app/Activity.java
BACKキーが押されたときに最終的に呼ばれるメソッドは
このonBackPressed()というメソッドです。
1884行目付近
public void onBackPressed() { finish(); }
finish()を呼んでいるので、Activityは終了します。
シンプルでいいですね。
まずはonKeyDownメソッドを見てみます。
1175行目付近
public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.ECLAIR) { event.startTracking(); } else { onBackPressed(); } return true; } //... }
Build.VERSION_CODES.ECLAIRなんてステキなコードが書いてありますね。
Eclair移行だとonKeyDownではonBackPressed()が呼ばれず、eventのstartTrackingが呼ばれます。
KeyEvent#startTracking()はTRACKINGというフラグを立てる処理だけしています。
Eclair以前のバージョンであれば、onKeyDown()でBACKキーが働くみたいですね。
続いてonKeyUpメソッドを見てみます。
1858行目付近
public boolean onKeyUp(int keyCode, KeyEvent event) { if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.ECLAIR) { if (keyCode == KeyEvent.KEYCODE_BACK && event.isTracking() && !event.isCanceled()) { onBackPressed(); return true; } } return false; }
Eclair移行は、onKeyDownで立てられたTRACKINGフラグをみて、onBackPressed()を呼んでます。
すでにハードキーの動きが違う部分があるんですね。
TRACKINGフラグがあるので、onKeyDownでフックしたままでも大丈夫そうですが
dispatchKeyEventでやっといた方が安心ですね。
まとめ
dispatchKeyEventが安心