AndroidでのListenerとCallbackの違い
Androidの勉強を始めてしばらくするとListenerやCallbackが出てきますが、Androidでの両者の違いをどう定義しているのか少し引っかかったので調べてみました。
大意としてはコールバックの方が根幹になる名詞で、リスナはコールバックに含まれてしまう、つまりどっちも同じでしょ、と言われればそうとも言えますが、個人的には「リスナ」と言われるとUIイベントをイメージし、「コールバック」と言われると内部処理をイメージしながら聞いています。
大意としてはコールバックの方が根幹になる名詞で、リスナはコールバックに含まれてしまう、つまりどっちも同じでしょ、と言われればそうとも言えますが、個人的には「リスナ」と言われるとUIイベントをイメージし、「コールバック」と言われると内部処理をイメージしながら聞いています。
一般的な定義
- Callback
呼び出し先の処理が終了した時点で(呼び出し元から指定された)関数が実行される事。
その為、呼び出し元から呼び出し先関数を実行する再に関数ポインタを渡しておく。
呼び出し先で何らかのイベントが発生した時にそれを検知し通知する為の仕組み。 - Listener
概要はコールバックと同じ。言語やフレームワークにより定義はマチマチ。
ちなみにJavaには関数ポインタが存在しないので、コールバックの実現にオブジェクトを使用している為か「リスナ」と表現される事が多い。
個人的にはUIイベント系がリスナ(イベントリスナ) 、UIイベント以外がコールバック、という感じで使い分けるものかなぁと漠然と考えていました。
Androidで気になったところ
しっくり版
Androidで最初の方に出会うのはイベントリスナだと思います。
Button button = (Button)findViewById(R.id.button);
button.setOnClickListener = (new View.OnClickListener(){
...
OnClickListenerインタフェースです。
なのでListenerという名前で実装されているのがしっくりきます。
クリックイベントを取得する = UIイベント
なのでListenerという名前で実装されているのがしっくりきます。
あれれ版
同じく最初の方に出会うこれ。
public boolean onKeyDown(int keyCode, KeyEvent event){
...
KeyEvent.Callback インタフェースで宣言されている onKeyDown() メソッドです。KeyEvent.Callback インタフェースはActivityやViewが実装してくれているのでそれらの内部で上記のようにいきなりオーバーライドして使用する事ができます。
でもイベントリスナ(= UIイベント)なのにインタフェース名が Callback …解せない…
そう言えば
SurfaceHolder.Callback というのもありました。
Surfaceの位置やサイズが変更された時に surfaceChanged(), Surfaceが作成/破棄された時に surfaceCreated(), surfaceDestroyed() が呼び出されます。
これは…
Surfaceの位置やサイズが変更された時に surfaceChanged(), Surfaceが作成/破棄された時に surfaceCreated(), surfaceDestroyed() が呼び出されます。
これは…
UIイベントはUIイベントなんだけど、通常ユーザ発じゃないUIイベント、という考えでリスナではなくコールバックとして実装されている、と考えれば納得…。
リファレンスを確認
上に記載したインタフェースに関してリファレンスを読んでみましたが、、、定義がない。
で、APIガイドで見つけました。
で、APIガイドで見つけました。
Event ListenersAn event listener is an interface in the View class that contains a single callback method. These methods will be called by the Android framework when the View to which the listener has been registered is triggered by user interaction with the item in the UI.イベントリスナはViewクラスのインタフェースで、1つのコールバックメソッドを含みます。これらのコールバックはリスナが登録されているViewの時UI中アイテムへのユーザ操作がトリガになりAndroidフレームワークから呼ばれます。
イベントリスナの定義として、Androidフレームワークから呼ばれるのはリスナ&コールバック共に存在するので置いておくとして、以下の2点は使えそうです。
- Viewクラスのインタフェース
- 1つのコールバックメソッドを含む
他リスナで色々調べると、上記2点の定義に当てはまらない(Viewクラスのインタフェースではない or 複数のコールバックメソッドが含まれる)のに xxx.Listener として定義されているインタフェースが出てくる事やイベントリスナの命名規則に当てはまらない(リスナインタフェースがOnXxxListenerでなくListenerで定義されてたり)ことから、ユーザ操作から生まれるAndroidフレームワークからの通知でも、リスナとイベントリスナを分けて定義しているようです。
- イベントリスナ
- Viewクラスのインタフェースとして定義されている
- リスナ
- Viewクラス以外のインタフェースとして定義されている
まだAndroidはやり始めなので、今後意識して見ていればこの辺りの定義はもう少し詰められるかも知れないです。
まとめ
- イベントリスナ
- ユーザ操作により発生する通知
- Viewクラスのインタフェース
- 1インタフェースに1つのコールバックメソッド
- 命名規則がある(ぽい)
- インタフェース OnXxxListener
- コールバックメソッド onXxx()
- リスナ設定メソッド setOnXxxListener
- リスナ
- ユーザ操作により発生する通知
- Viewクラスのインタフェースではない
- 1インタフェースに1〜複数のコールバックメソッド
- コールバック
- 基本的には内部処理結果の通知
という感じでしょうか。
自分で作るとしたら、
- UI系コントロールを拡張する時、根本部分ならイベントリスナ
- UI系コントロールを拡張する時、下位コントロール限定ならリスナ
- 内部処理ならコールバック
として実装すると何となくAndroidに合う気がします。。
最後に
KeyEvent.Callbackに関してはなぜリスナでなくコールバックとして実装されているのかまだピンと来ていません。View系クラス以外でも使えるようにと考えたとしても、Listenerという名前で定義してくれた方がスッキリするんだけどな、と思うのは
・コールバックを内部処理で使う
・リスナをUIイベント系で使う
と習慣づいてしまっているからかも知れません。
・コールバックを内部処理で使う
・リスナをUIイベント系で使う
と習慣づいてしまっているからかも知れません。
コールバックの仕組みをデザインパターンに落としたものにObserverパターンというものがありますが、リスナ系にしてもコールバックにしても仕組み自体は同じものなので今回省いてます。