てっとりばやくいうと、onDraw()とかがソレ。
正確にはイベント・リスナーというらしい。
class 外部でイベントが発生すると、それに対応したmethod が実行される…と。
onDraw() でいえば、
1. 画面更新イベントが発生 2. OSがclass のonDraw() を実行
で、onDraw()の実行処理が「イベントハンドラ」。
こんなトコだろうかね。
ボタンなんかもそうだね。
押されたら、その処理をbutton.classの中で行うんじゃなくて、別のclass でやってもらう。
button.class 「ボタン」 ↓押された View.class onClick() メッセージ表示 「押された」
リスナーが「通知先」で、その処理が「イベントハンドラ」。
こういう仕組みが、Android にはそこかしこにある。
おそらく、ViewのonDraw() のような、よく使うもの、必須となるようなものはあらかじめclassに登録されているのだろうね。
では、登録されていないものは…?
implements でそれを埋め込むことになる。
つまり、「このclass で、○○イベントを受け取ります」って「宣言」するってことやね。
で? その構造はどうやって作るのよ?
自前classでも作りたくなることは多々あるよね。
例えば、スレッドで処理をしていて、その処理が終わったとか、結果を別classへ送りたいとか。
複数スレッドを動かしてると、特に必要性を感じるね。
ということで。
「ボタン」を例に、サンプルを作ってみた。
[クリック] ↓ MyButton.onTouchEvent() ↓[通知] _listener.onClick() ↓ [メッセージ更新]
◆listener_Test ・2つのオブジェクトを生成。 ・MyButton のリスナーに、ListenerViewを登録 _listener = ListenerView ■MyButton onTouchEvent() ・クリック・イベントを受信したら、リスナーに通知。 _listener.onClick() ■ListenerView onClick() ・イベントを受信すると、メッセージを更新
listener_Test.java
package com.migimaki.android; import android.app.Activity; import android.os.Bundle; import android.widget.FrameLayout; import android.view.ViewGroup; import com.migimaki.android.MyButton.onClickListener; public class listener_Test extends Activity { private final int WC = ViewGroup.LayoutParams.WRAP_CONTENT; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); FrameLayout frameLayout = new FrameLayout(this); // オブジェクトを生成 ListenerView LV = new ListenerView(this); MyButton myButton = new MyButton( this ); // リスナー登録 myButton.setOnClickListener( (onClickListener)LV ); // レイアウト追加&表示 frameLayout.addView( LV, createParam(WC, WC)); frameLayout.addView( myButton, createParam(WC, WC)); setContentView(frameLayout); } private ViewGroup.LayoutParams createParam(int w, int h){ return new ViewGroup.LayoutParams(w, h); } }
MyButton.java
package com.migimaki.android; import android.content.Context; import android.widget.ImageView; import android.view.MotionEvent; public class MyButton extends ImageView { public MyButton( Context c ){ super( c ); setImageResource( R.drawable.icon ); } private onClickListener _listener = null; //リスナー // リスナーの登録 public void setOnClickListener( onClickListener listener ){ _listener = listener; } // click イベント public boolean onTouchEvent( MotionEvent event ){ _listener.onClick(); // イベントの通知 return true; } // イベントの通知先 public interface onClickListener{ public void onClick(); } }
ListenerView.java
package com.migimaki.android; import android.content.Context; import android.widget.TextView; import android.graphics.*; import com.migimaki.android.MyButton.onClickListener; public class ListenerView extends TextView implements MyButton.onClickListener { public ListenerView( Context c ){ super( c ); setPadding( 50, 50, 200, 300); //文字表示エリア setTextColor( Color.WHITE ); setText("Listenerテスト"); } // イベントの受信 private int count=0; public void onClick(){ count++; setText( ""+count+ "回、押された?!" ); } }
作ってみたものの…イマイチなサンプルだなぁ。(^_^;
本当は、2つのclassで納めたかったんだけど…。
ボタンじゃなく、スレッドを例にすればよかったかな。
ちなみに、interface 宣言したものは、implements 先で設置が求められる。
設置されていないと、eclipse がエラー出してくれるよ。