Listener ~リスナーってなによ?

 てっとりばやくいうと、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 がエラー出してくれるよ。