EventMultiCaster

以前にも書いたが、Android SDKの一般的なビューはイベントハンドラがシングルキャストであり、複数のリスナを登録することができない。

シングルキャスト

暫く放置していたのだが、やはりマルチキャストに対応しなければならない要件が出てきたのでそのためのクラスを作ってみた。

  • IListenerMulticaster.java
public interface IListenerMulticaster {
    IListenerMulticaster pushListener(L l);
    L popListener();
    void removeListener(L l);
    int size();
}

IListenerMulticasterはEventLisatenerの代わりに使うインタフェース。
pushListenerはaddListenerの方が分かり易いかもしれない。

  • AbstractListenerMulticaster.java
public abstract class AbstractListenerMulticaster implements IListenerMulticaster {
    protected Stack listeners;

    public AbstractListenerMulticaster() {
        super();
        this.listeners = new Stack();
    }
    @Override
    public IListenerMulticaster pushListener(L l) {
        if ( l != null ) {
            this.listeners.push(l);
        }
        return this;
    }
    @Override
    public L popListener() {
        return this.listeners.pop();
    }
    @Override
    public void removeListener(L l) {
        this.listeners.remove(l);
    }
    
    @Override
    public int size() {
        return this.listeners.size();
    }
}

Androidの場合イベントリスナの型階層が無いため(残念だ)、具象クラスはイベントリスナの型毎に用意しなくてはならない。
例えば、クリックイベントのためのリスナをマルチキャストにするためのクラスは、上記のテンプレートから継承して以下のように実装する。

  • ClickListenerMulticaster.java
public class ClickListenerMulticaster extends AbstractListenerMulticaster implements OnClickListener {
    @Override
    public void onClick(View v) {
        for ( OnClickListener l : this.listeners ) {
            l.onClick(v);
        }
    }
}

実際には以下のように使う。

@Override
public void onCreate(Bundle savedInstanceState) {
    Button button = (Button)this.findViewById(R.id.Button01);
    ClickListenerMulticaster caster = new ClickListenerMulticaster();
    caster.pushListener(new OnClickListener(){
        @Override
        public void onClick(View v) {
            Toast.makeText(Addressdroid.this, "I am listener 1", Toast.LENGTH_SHORT).show();
        }});
    caster.pushListener(new OnClickListener(){
        @Override
        public void onClick(View v) {
            Toast.makeText(Addressdroid.this, "I am listener 2", Toast.LENGTH_SHORT).show();
        }});
    caster.pushListener(new OnClickListener(){
        @Override
        public void onClick(View v) {
            Toast.makeText(Addressdroid.this, "I am listener 3", Toast.LENGTH_SHORT).show();
        }});
    button.setOnClickListener(caster);
}

実行するとボタンクリック時、トーストに
[I am listener 1]
[I am listener 2]
[I am listener 3]
と順に表示される。
思いつきでいきなり書いたので、バグはあるかもしれない。ご容赦。

追記:
やはり、イベントリスナの型毎に具象クラスを起こすのが面倒だな。あと、せっかくIListenerMulticasterというインタフェースを作ったにも関わらず、ルートのイベントリスナ型が無いため、

01|    IListenerMulticaster caster = new ClickListenerMulticaster();
02|    button.setOnClickListener(caster);

という書き方ができない(02行目がエラー)のも恰好がよくないな。