PS: 最大の努力を尽くし、最悪の事態に備える。怠けたことはいつか自分に返ってくる。
Android のイベントディスパッチメカニズムは非常に重要な要素であり、Android のイベントディスパッチに関するいくつかの知識をまとめ、4 つの記事に分けて書く予定です。
この記事は最初の記事であり、イベントの配信プロセスを概説し、読者がイベントの配信について初めて理解できるようにすることを目指しています。内容は以下の通りです:
- View と ViewGroup
- MotionEvent オブジェクト
- View のイベント配信
- まとめ
View と ViewGroup#
Android アプリケーションのすべてのコンポーネントは View クラスを継承しています。View クラスは Android のすべての UI コンポーネントの基本クラスであり、View は ViewGroup という重要なサブクラスを持っています。ViewGroup は通常、他の View のコンテナとして使用され、通常は通常の View や他の ViewGroup を含むことができます。View と ViewGroup の関係によって、LinearLayout などは単なる View だけでなく、ViewGroup でもあります。LinearLayout 内にはさまざまな 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 に戻され、最終的には 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 のイベントディスパッチメカニズムをソースコードの観点から見ていきます。