Android——キーイベントの配信処理フローの解析 KeyEvent

序文

今回はAndroid TvにおけるキークリックイベントKeyEventの配信処理を整理してみようと思います。クリック イベント メカニズムに関しては、配布、インターセプト、処理の 3 つの主要なプロセス、またはdispatchTouchEvent、onInterceptTouchEvent、onTouchEvent、または消費を示す場合は true を返し、処理しない場合は false を返すなど、オンライン情報は非常に完全です。 ; という格言もあります 全体のプロセスは U 字型の配布プロセスであり、部長は従業員にタスクを発行してフィードバックなどを処理します。先人たちは乾物をすでに整理してくれていますし、できるだけ一般的でわかりやすいものを書いてくれています。

しかし、今日の記事のトピックは次のとおりです: KeyEvent 配布プロセス

わかりやすく言うと、テレビのリモコン ボタンのクリック イベントをディスパッチして処理するプロセスですが、おそらくまだ気づいていないかもしれません。考えてみてください。携帯電話はタッチ スクリーンのクリック イベントですが、リモコンはボタンのクリック イベントです。2 種類のイベントの配布および処理メカニズムは当然異なります。これら 2 種類のイベント配布メカニズムを混同してください。

最も単純な違いは、Tv 開発では、タッチスクリーン携帯電話のように、dispatchTouchEvent、onInterceptTouchEvent、および onTouchEvent にdispatchTouchEvent、onInterceptTouchEvent、およびonTouchEventが使用されなくなったことです。

プロセス

今回はKeyEventの配布処理だけをViewツリーに整理しますが、簡単に言うと、あるActivityインターフェースでリモコンのボタンをクリックし、そのボタンイベントが現在のActivityでどのように動作するかということです。処理。
ここに画像の説明を挿入
フローチャートに関係する主なメソッドとクラスは次のとおりです。

(PhoneWindow$)DecorView ->dispatchKeyEvent()
アクティビティ ->dispatchKeyEvent()
ViewGroup ->dispatchKeyEvent()
View ->dispatchKeyEvent()
KeyEvent ->dispatch()
View ->onKeyDown/Up()

ハードウェア層とフレームワーク層での主要なイベントの取得、配布、処理は難解すぎて理解できません。アプリケーション層のイベント配信処理はまだよく理解されていない部分があるため、今回はViewツリー内の配信処理について整理する。

プロセス分析

ps: Activityインターフェースでリモコンボタンをクリックすると、Action_DownとAction_Upという2つのKeyEventが配信処理として存在しますが、配信処理は同じで、最終的にonKeyDownかonKeyUpに引き渡される点が異なります。処理するアクティビティまたはビューの。

配布プロセス

KeyEvent イベントを受信すると、まず配布のために (PhoneWindow$)DecorView のdispatchKeyEvent() に渡され、DecorView はアクティビティのdispatchKeyEvent() を呼び出してから、さらに配布するためにアクティビティに渡します。
ここに画像の説明を挿入
Activity は最初に PhoneWindow オブジェクトを取得し、次に PhoneWindow の superDispatchKeyEvent() を呼び出し、PhoneWindow は DecorView の superDispatchKeyEvent() を呼び出し、DecorView は super.dispatchKeyEvent() を呼び出してイベントを配布のために親クラスに送信します。 FrameLayoutのdispatchKeyEvent()は実装されていないため、実際にはViewGroupのdispatchKeyEvent()に渡されて配信されます。
ここに画像の説明を挿入ここに画像の説明を挿入ここに画像の説明を挿入
1. ViewGroup ディストリビューションのロジックはまだ理解していませんが、ViewGroup が現在のフォーカスのサブビューを再帰的に検索し、フォーカスされているサブビューのdispatchKeyEvent() ディストリビューションにイベントを送信することは一般的にわかっています。コードのこの部分が研究対象であることを見つけます。

2. 以上はKeyEventイベントの配信処理ですが、タッチパネル携帯電話のイベント送信とは少し異なりますので、上記の配信イベント関連クラスの該当配信メソッドを書き換えないと、必ずKeyEventイベントが配信されてしまいます。 onInterceptTouchEvent のような特定のレイヤーでインターセプトされる操作がないため、トップレベルの DecorView から特定のサブ View に分散されます。

処理の流れ

ps: KeyEvent イベントを処理する場所は 2 つだけです。1 つはアクティビティ、もう 1 つは特定のビューです。ViewGroup は配布のみを担当し、イベントを消費しません。TouchEvent と同様に、true を返すとイベントが消費されたことを意味し、false を返すとイベントがまだ存在することを意味します。

KeyEvent イベントが特定のサブビューのdispatchKeyEvent()に割り当てられると、ビューはまず OnKeyListener リスナーが設定されているかどうかを確認し、設定されている場合は OnKeyListener.onKey() メソッドをコールバックしてイベントを処理します。
ここに画像の説明を挿入View が OnKeyListener を設定しない場合、または onKey() が false を返した場合、View は View 自体の onKeyDown/Up() をコールバックし、KeyEvent のdispatch() メソッドを呼び出してイベントを処理します。
ここに画像の説明を挿入
ビューの onKeyUp メソッドが書き換えられておらず、イベントが [OK] (確認) ボタンの Action_Up イベントである場合、ビューは OnClickListener リスナー セットがあるかどうかを確認し、OnClickListener.onClick() を呼び出してイベントを消費します。つまり、View に OnClickListener リスナー セットがあり、イベントが上記の 2 つの手順で消費されない場合は、 onClick() で消費する必要があります。ブール値は返されませんが、View が内部のdispatchKeyEvent() でイベントを onClick にディスパッチすると、イベントが消費されたことを示すためにデフォルトで true が返されます。
ここに画像の説明を挿入
ビューがイベントを処理しない場合、つまり、OnKeyListener も OnClickListener も設定されておらず、onKeyDown/Up() が false を返した場合、イベントをディスパッチする元の方法に戻り、現在のイベントが処理されていないことをアクティビティに通知します。 false メッセージが返されると、KeyEvent のdispatch() を通じてアクティビティ自身の onKeyDown/Up() イベントを呼び出し、そのイベントを処理のためにアクティビティ自体に渡します。これは、Activity で onKeyDown/Up() をオーバーライドしてクリック イベントを処理する一般的な方法ですが、ここでの処理は最後に受信されるため、イベントがここに到達する前に消費される可能性が非常に高いことに注意してください。

まとめ

ここに画像の説明を挿入
全体的な分散処理フローは上の図に示されています (手が震えています。それ以外は直線です)。重要な点をいくつかまとめることができます。

1. DecorView についてあまり詳しくない場合は、次の点に基づいて、Activity、ViewGroup、View など、頻繁に触れる点にのみ焦点を当てることができます。

2. イベント配布: Activity は最初に KeyEvent イベントを取得しますが、それ自体で処理をインターセプトする方法はありません (ここで異論があるはずです。後で説明します)。その後、イベントを ViewGroup に配布します。ViewGroup は再帰的にのみ実行できます。サブビューの場合、イベントは ViewGroup で消費されません。最後に、サブビューがイベントを受信し、配布プロセスが終了し、イベント処理が開始されます。

3. イベント処理: イベントを処理できるのは、Activity と View のみです。View は、状況に応じて、OnKeyListener、OnClickListener、または onKeyDown/Up() のいずれでイベントを処理するかを選択できます。Activity は、onKeyDown/Up() でのみイベントを処理できます。

4. イベント処理は 4 つの場所に要約できます。これらの順序は、View の OnKeyListener.onKey()、onKeyDown/Up()、OnClickListener.onClick()、Activity の onKeyDown/Up() です。4 つの場所のどこかに到達すると、イベントは消費され、つまり true が返され、イベントは後続の処理メソッドに渡されません。

なぜアクティビティはイベントをインターセプトして単独で処理できないと言えるのでしょうか?

タッチスクリーンのTouchEventクリックイベントの仕組みでは、onInterceptTouchEvent()をtrueを返すように書き換えることで、インターセプトイベントの配信を停止して自分でイベントを処理することができますが、KeyEventにはそのようなメソッドがないため、dispatchKeyEvent()がイベントの配布にのみ使用されます イベントの処理は onKeyDwon/Up、onKey()、onClick() で行われます この場合、アクティビティにはイベントの配布をインターセプトして独自の onKeyDown/Up() に渡す方法がありません。

ただし、dispatchKeyEvent()はイベント配信しかできないと誰が定めているので、規格上理論的にはActivityがイベント配信をインターセプトして単独で処理することはできないのですが、実際のプログラミングでは、イベント配信を処理するためにActivityのdispatchKeyEvent()を書き換えている人によく遭遇します。 events を呼び出し、 true または false を返してイベントの配布を停止します。

使用するシーン

KeyEvent イベントの配布と処理のプロセスは一般にどのように行われるかを知る必要があるため、興味がある場合は、ソース コードをもう一度参照し、自分でフローチャートを描くとよりよく理解できます。まず分散処理フローを整理し、その使用方法、分散処理メソッドの書き換え方法を理解します。次に、いくつかの使用シナリオについて説明します。

1.アクティビティのdispatchKeyEvent()を書き換えます - 最も一般的に使用されます

栗を採りましょう。
ここに画像の説明を挿入
これは TV 開発では非常に一般的であり、Activity のdispatchKeyEvent() を書き換えてから、いくつかの作業を前処理するか、特定のキーをインターセプトすることがよくあります。

上記のコードを理解できますか? このコードが左右のボタンをインターセプトすることをすでに知っている場合は、さまざまな戻り値の関数、なぜ return true、return false、return super.dispatchKeyEvent() があるのか​​をご存知ですか?

最初に結論について話します。ここでの true と戻りの false はどちらもキーのインターセプトの役割を果たすことができます。つまり、子 View はイベントの配布や処理を受け取りません。また、Activity の onKeyDown/Up() も受け取りません。メッセージは受信しません。

これを理解するには、まずリターンとは何かを理解する必要があります。リターンとはリターンを意味します。どのような状況でリターンする必要があるのでしょうか?呼び出したメソッドがフィードバックを提供する必要があるという意味ではないでしょうか。したがって、リターンのメッセージは上位レベルの呼び出し元 はい。したがって、return は上位レベルの呼び出し元の動作にのみ影響します。以下の図に示すように、Activity.dispatchKeyEvent() の呼び出しは DecorView のdispatchKeyEvent() 内にあります。
ここに画像の説明を挿入
したがって、Activity は true または false を返すため、DecorView の動作にのみ影響します。イベント配信を傍受しますか?

これは、実際にはActivity.javaのdispatchKeyEvent()にイベント振り分けロジックが実装されているためで、ActivityのdispatchKeyEvent()メソッドを書き換えると、Javaの特性に合わせてプログラムが記述したdispatchKeyEvent()を実行するようになるためです。基本クラスの Activity.java は実行されないため、書き換えたメソッドにイベント配信ロジックを自分で実装することはなく、当然イベントの配信は停止します。super.dispatchKeyEvent() が返されたときにイベントが引き続き配布されるのはこのためです。これは、最終的に基本クラス Activity.java のdispatchKeyEvent() メソッドを呼び出してイベント配布のロジックを実行するためです。

Activityでtrueかfalseを返すのはインターセプトを意味するので何か違いはあるのでしょうか?

もちろん、これは DecorView の動作に影響するためです。たとえば、リモコンの矢印キーをクリックすると、インターフェイスにフォーカスが続きます。ロジックのこの部分は、実際には DecorView の上位レベルの呼び出し元に実装されています。アクティビティが true を返した場合、DecorView が true を返し、上位レベルは DecorView が true を返した結果に従ってフォーカスの移動を停止します。これは、Activity のdispatchKeyEvent()を書き換えてtrueを返して停止するという共通の原則です。フォーカスの移動。次に、Activity が false を返し、DecorView も false を返した場合、上位レベルは引き続きフォーカス移動のロジックを実行し、インターフェイス上のフォーカスは引き続き移動しますが、Activity のアクティブ化はトリガーされません。および View: イベントの配布および処理メソッド (アクティビティによってインターセプトされているため)。

最後に、別の質問があります。View または ViewGroup でdispatchKeyEvent() を書き換えると、Activity と同じ効果がありますか?

true または false または super を返す意味は同じですが、理解する必要がある階層があります。上層:Activity、中層:ViewGroup、下層:View。

どの層のdispatchKeyEvent()を書き換えても、trueまたはfalseを返した場合、自層を含む下位層はイベント配信処理を受けず、上位層はイベント配信処理を受け取ります。インターセプト効果はこのレイヤーと下位レイヤーにのみ作用し、上位レイヤーは返された値に応じてのみ影響を受けるためです。

たとえば、ViewGroup で true が返された場合、Activity の onKeyDown/Up() は消費されるためトリガーされません。false が返された場合、イベントは Activity によって処理されます。ただし、true または false を返すかどうかに関係なく、子 View のdispatchKeyEvent() やさまざまな onClick() などのイベント処理メソッドはトリガーされません。

2. アクティビティの onKeyDown/Up() を書き換えます - 最も一般的に使用されます

イベントがここに来ることができるということは、イベントが子ビューによって消費されないことを意味し、これは、私たちが触れることのできるレイヤー内でイベントを処理する最後の場所です。ここで何らかの処理を行ったとしても、true を返す必要はありません。例えば矢印キーイベントの場合、ここでtrueを返すと上司のフォーカスを止める動きに影響するので状況によります。

3. 特定のビュー (TextView など) に OnKeyListener() を設定します - 一般的に使用されます

これは非常に一般的で、アクティビティ内の特定のコントロールのオブジェクトを取得し、クリック イベント リスナーを設定して、何かを実行します。

4. 特定のビュー (ボタンなど) に OnClickListener() を設定します - 一般的に使用されます

これはより一般的なはずです。setOnClickListener です。明確にするために、多くのシナリオではコントロールのクリック イベントを監視する必要があります。リスナーは [OK] (確認) ボタンの Action_Up イベントをリッスンします。

総括する:

dispatchKeyEvent(): このメソッドをアクティビティまたはカスタム ViewGroup タイプ コントロールで書き換えるのが一般的です。場合によっては、イベントの配布を開始する前にいくつかの作業を前処理する必要がある場合や、特定のキーをインターセプトする必要がある場合があります。インターセプトに注意 各種戻り値のスコープと役割は十分です。すべてのキーをインターセプトする必要はなく、Android システムはデフォルトで多くの特別なキーを処理するため、一部のキーは引き続き配布する必要があるため、通常は return super が含まれます。

super の意味を明確にします。書き換えられたメソッドは通常、イベントの配布を実行するための dispatchKeyEvent などのデフォルトのロジック作業を実行します。書き換える際には、親クラスのロジックを引き続き使用する必要があるかどうかに注意してください。

残された問題

1. ボタンがクリックされるたびに、Action_DownとAction_Upの2つのイベントが発生する 現在、このようなシナリオでは、アクティビティAからアクティビティBを開くと、アクティビティAでAction_DownとAction_Upが分散処理され、その後、Action_Upが実行されます。アクティビティ B で配布および処理されます。

本来の考え方は、アクティビティ A が処理のために Action_Up イベントをアクティビティ B に渡すというものですが、アクティビティ A では最初に Action_Up を消費してから true を返し、アクティビティ B が引き続き Action_Up イベントを再配布することがわかりました。そのため、KeyEvent イベントが 2 つのアクティビティにどのように分散されるかについてはまだよくわかっていませんが、この部分は ViewRootImpl と PhoneWindow にあるはずです。次回の記事でこの部分を整理する予定です。

2. TV 開発で最も重要かつ厄介な点はフォーカスの問題です。リモコンの矢印キーをクリックすると、フォーカスの移動を制御できます。必要に応じてフォーカスを制御する必要がある場合があります。たとえば、よくやるのは、フォーカスが境界に達したときに書き換えるということですが、dispatchKeyEventでtrueを返してフォーカスの移動を止めるのですが、なぜこんなことができるのでしょうか?実際、コンテンツのこの部分は DecorView のdispatchKeyEventにもあります。DecorView はハイエンド SDK の単一クラスを抽出しました。それが見つからない場合は、PhoneWindow に移動して見つけてください。古い SDK では、 DecorView は PhoneWindow の内部クラスであり、この部分の内容も次回の整理のために保存されます。

元リンク:AndroidキーイベントKeyEvent配信処理フロー解析

おすすめ

転載: blog.csdn.net/u012230055/article/details/103824930