PS:最大の努力を尽くし、最悪の事態を想定せよ。かつてあなたが怠けた分は、いつか必ず自分に返ってくる。
Android のイベント配信メカニズムは非常に重要な内容であり、Android のイベント配信に関する知識をまとめるために、4 つの記事に分けて書く予定です。内容は以下の通りです:
本記事は第一篇であり、全体の流れを説明し、読者がイベント配信についての初歩的な理解を得られるようにすることを目的としています。内容は以下の通りです:
- View と ViewGroup
- MotionEvent オブジェクト
- View のイベント配信
- まとめ
View と ViewGroup#
Android アプリケーションのすべてのコンポーネントは View クラスを継承しています。View クラスは Android におけるすべての UI コンポーネントの基底クラスであり、重要なサブクラスとして ViewGroup があります。ViewGroup は通常、他の View のコンテナとして使用され、普通の View や他の ViewGroup を含むことができます。View と ViewGroup のこの関係によって、全体の View ツリーの構造が形成されます。例えば、LinearLayout は単なる View であるだけでなく、ViewGroup でもあり、さまざまな View を含むことができます。もちろん、この View も ViewGroup であることができます。
Android デバイスでは、操作は主にさまざまなジェスチャーに依存しています。例えば、スワイプ、ドラッグ、クリックなどの操作は、Android デバイスとのインタラクションを非常に便利にします。前述のように、異なる View は異なる階層にあります。では、操作を行う際に特定の View がどのように正しく反応するのか、異なる View 間でスワイプの競合が発生することはあるのかという問題が生じます。答えは肯定的です。このような問題を解決するためには、View の動作メカニズム、さまざまなイベントの配信プロセス、および具体的な配信対象を十分に理解する必要があります。
MotionEvent オブジェクト#
Android におけるイベント配信は MotionEvent オブジェクトによって行われます。MotionEvent には、さまざまなイベント発生位置に関連する関数や関連するイベントタイプが多く封装されています。各 MotionEvent は一連のアクションを含んでいます。例えば、指が画面に触れた瞬間、システムは一連のタッチイベントオブジェクトを生成します。各タッチイベントオブジェクトは異なるアクションを表します。例えば、押下、スワイプ、離すなどのアクションは、それぞれ ACTION_DOWN、ACTION_MOVE、ACTION_UP などの具体的なイベントに対応しています。この一連のイベントは一般的に ACTION_DOWN イベントから始まり、中間にいくつかの ACTION_MOVE イベントがあり、最後に ACTION_UP で終了します。さらに、イベントが遮断された場合は ACTION_CANCEL イベントがトリガーされます。要するに、Android のイベント配信の対象は MotionEvent オブジェクトです。MotionEvent オブジェクトが生成されると、システムはこのイベントを最終的にこのイベントを消費できる View に配信します。
View のイベント配信#
Android におけるイベント配信は実際には View のイベント配信を指します。View のイベント配信は主に以下の 3 つのメソッドから成ります:
- dispatchTouchEvent()
- interceptTouchEvent()
- onTouchEvent()
これらの 3 つのメソッドはそれぞれイベントの配信、イベントの遮断、イベントの処理に対応しています。なお、View には interceptTouchEvent () メソッドがありません。一方では、View の中に他の子 View がないため、イベントを遮断する必要がなく、他方では View の interceptTouchEvent () メソッドが true を返すと理解できます。イベント自体はその View によって遮断され、消費するかどうかは onTouchEvent () の事です。いずれにせよ、View はイベントの遮断を考慮しません。
Android のイベント配信は Activity の dispatchTouchEvent () メソッドから始まり、一連の伝達を経て ViewGroup の dispatchTouchEvent () メソッドに配信されます。現在の ViewGroup がイベントを遮断しない場合、子 View にイベントを配信し続けます。そして、このプロセスはどの View が処理するまで続きます。もしどの View もそのイベントを処理しなかった場合、イベントは親 View から子 View へと最深部の View に伝達され、イベントは親 View の方向に戻り、最終的に Activity の onTouchEvent () で処理されます。
もし現在の ViewGroup がそのイベントを遮断した場合、イベントは子 View に配信されず、その onTouchEvent () メソッドで処理されます。もちろん、イベントが処理されるかどうかは、対応する onTouchEvent () メソッドの戻り値によります。もし onTouchEvent () メソッドが true を返せば、イベントは消費されたことを意味し、逆に false を返せば、イベントは消費されず、親 View の onTouchEvent () メソッドで処理されます。もし親 View の中で処理されなければ、最終的に Activity の onTouchEvent () で処理されます。
もしイベントが配信プロセス中にある View によって処理された場合、例えば ACTION_DOWN イベントが処理された場合、その後の ACTION_MOVE、ACTION_UP イベントはそのイベントを処理した View によって直接受け取られます。つまり、あるイベントがある View によって処理されると、その後の一連のイベントはこれらのイベントを遮断するかどうかを判断せずに直接受け取ります。なぜなら、完全なイベントシーケンスは常に ACTION_DOWN イベントから始まり、その後にいくつかの ACTION_MOVE イベントが続き、最後に ACTION_UP で終了するからです。
まとめ#
Android のイベント伝達メカニズムの主な内容は上記の通りですが、実際の配信プロセスは確実により複雑です。次回はソースコードの観点から Android のイベント配信メカニズムを見ていきます。