2010年10月25日月曜日

dispatchKeyEventについて


androidのkeyイベントについて調べたので、
忘れないようにメモしとく。

結論から書くと、androidのキーイベントの
イベント配信の方法は、GTKと同じで、
親から順番にイベントが通知されていき
最終的にフォーカスが当たっている
もしくは当たっていたアイテムにキーイベントが通知される。
といったものだ。
うーん。子供からキーイベントが通知されて、
親にバブルアップしていったほうが拡張性が高いんだがな。。。


アプリを作る人に最初に見えるのは、
ActivityのdispatchKeyEventで、
そこからGroupView->View->ユーザ定義のView
といった具合だ。
なので、
上下キーをこっちのViewに通知して
左右キーはあっちのViewに通知する
みたいな処理をしようと思ったら、
ActivityでdispatchKeyEventをOverrideして、
そこでイベント処理をしてやらなければいけない。
しかもフォーカス依存になっているから、
そのたびにフォーカスの移動しなければいけないのでは。。。
やっぱandroidって、タッチパネル前提のプラットフォームだなぁと
改めて感じた。

ちなみに、確認のために書いてみたのは
下のようなコードです。


HelloAndroid.java

package com.example.helloandroid;

import java.util.Random;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnKeyListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.content.Intent;


public class HelloAndroid extends Activity{

@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_UP) {
switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_0:
Log.v("HelloAndroid","Activity KEYCODE_0");
return true;
default:
}
}
Log.v("HelloAndroid","Activity");
return super.dispatchKeyEvent(event);
}

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);


Button b_true = (Button)findViewById(R.id.button_true);
b_true.setOnKeyListener(new OnKeyListener(){
public boolean onKey(View v, int keyCode, KeyEvent event){
if (event.getAction() == KeyEvent.ACTION_DOWN) {
Log.v("HelloAndroid","button true");
return true;
}
return false;
}
});

Button b_false = (Button)findViewById(R.id.button_false);
b_false.setOnKeyListener(new OnKeyListener(){
public boolean onKey(View v, int keyCode, KeyEvent event){
if (event.getAction() == KeyEvent.ACTION_DOWN) {
Log.v("HelloAndroid","button false");
}
return false;
}
});

ListView listView = (ListView) findViewById(R.id.listview);
String[] items = new String[] {"First", "Second", "Third", "Fourth"};

ArrayAdapter adapter = new ArrayAdapter (this,
android.R.layout.simple_list_item_1,
items);

listView.setAdapter(adapter);
listView.setOnKeyListener(new OnKeyListener() {
public boolean onKey(View v, int keyCode, KeyEvent event){
if (event.getAction() == KeyEvent.ACTION_DOWN) {
Log.v("HelloAndroid","listView false");
}
return false;
}
});

LinearLayout linear = (LinearLayout)findViewById(R.id.parent);
linear.setOnKeyListener(new OnKeyListener() {
public boolean onKey(View v, int keyCode, KeyEvent event){
if (event.getAction() == KeyEvent.ACTION_DOWN) {
Log.v("HelloAndroid","linear false"); // これは永久に出ません。なぜならLinearLayoutではdispatchしているだけだから。
}
return false;
}
});
}
}


ほかにも色々書いてあったコードから、
抜き取ったので、きちんと動くかはナゾ。

いかは、コールバック

HelloAndroid [Android Application]
HelloAndroid [Android Application]
DalvikVM[localhost:8617]
Thread [<3> main] (Suspended (breakpoint at line 97 in HelloAndroid$5))
HelloAndroid$5.onKey(View, int, KeyEvent) line: 97
ListView(View).dispatchKeyEvent(KeyEvent) line: 3678
ListView(ViewGroup).dispatchKeyEvent(KeyEvent) line: 746
ListView.dispatchKeyEvent(KeyEvent) line: 1943
LinearLayout(ViewGroup).dispatchKeyEvent(KeyEvent) line: 748
FrameLayout(ViewGroup).dispatchKeyEvent(KeyEvent) line: 748
LinearLayout(ViewGroup).dispatchKeyEvent(KeyEvent) line: 748
PhoneWindow$DecorView(ViewGroup).dispatchKeyEvent(KeyEvent) line: 748
PhoneWindow$DecorView.superDispatchKeyEvent(KeyEvent) line: 1655
PhoneWindow.superDispatchKeyEvent(KeyEvent) line: 1102
HelloAndroid(Activity).dispatchKeyEvent(KeyEvent) line: 2038
HelloAndroid.dispatchKeyEvent(KeyEvent) line: 40
PhoneWindow$DecorView.dispatchKeyEvent(KeyEvent) line: 1631
ViewRoot.deliverKeyEventToViewHierarchy(KeyEvent, boolean) line: 2368
ViewRoot.handleFinishedEvent(int, boolean) line: 2338
ViewRoot.handleMessage(Message) line: 1641
ViewRoot(Handler).dispatchMessage(Message) line: 99
Looper.loop() line: 123
ActivityThread.main(String[]) line: 4363
Method.invokeNative(Object, Object[], Class, Class[], Class, int, boolean) line: not available [native method]
Method.invoke(Object, Object...) line: 521
ZygoteInit$MethodAndArgsCaller.run() line: 860
ZygoteInit.main(String[]) line: 618
NativeStart.main(String[]) line: not available [native method]
Thread [<13> Binder Thread #2] (Running)
Thread [<11> Binder Thread #1] (Running)
Thread [<15> Binder Thread #3] (Running)

0 件のコメント:

コメントを投稿