インタビュアー1:Androidのイベント配信メカニズムについて詳しく説明してください
この質問は、多くの面接会社が尋ねる古典的な面接の質問ですが、面接官はしばしば無視します。
私はたくさんのブログを読んだり、たくさんのコードを読んだりしましたが、そのほとんどは長い記事であり、読むのに役立ちません。
メインラインへのステップは3つだけです:Activity-> ViewGroup-> View
アクティビティとビューには、イベント配信を制御するための2つのメソッドしかありません。dispatchTouchEvent()、onTouchEvent();
ViewGroupには、配信を制御する3つのメソッドがあります。dispatchTouchEvent()、onInterceptTouchEvent()、onTouchEvent();
次に、写真を使用して、それを段階的に配布する方法を説明します。
総括する:
dispatchTouchEvent、onTouchEvent、1.は真が返され、最終的なイベントの配信です。falseを返すの は、親ビューに戻るonTouchEventメソッドです。
2. ViewGroupは、それ自体を独自のonTouchEventに配布したいので、イベントをインターセプトするには、インターセプターonInterceptTouchEventメソッドがtrueを返す必要があります。
3. ViewGroupのインターセプターonInterceptTouchEventはデフォルトではインターセプトされないため、super.onInterceptTouchEvent()= returnfalseを返します。
4. Viewにはインターセプターがありません。Viewがイベントを独自のonTouchEventに配布できるようにするために、ViewのdispatchTouchEventのデフォルトの実装(スーパー)は、イベントを独自のonTouchEventに配布することです。
ViewGroupとViewのdispatchTouchEventはイベント配信用であるため、このイベントは4つのターゲットに配信される可能性があります。
注:------>以下は、イベントターゲットが実行する必要があることを表しています。
1.自分で消費し、配達を終了します。-------> trueを返します ;
2.独自のonTouchEventを処理する-------> call super.dispatchTouchEvent()システムはデフォルトでonInterceptTouchEventを呼び出し、onInterceptTouchEventがtrueを返すと、処理のためにイベントを独自のonTouchEventに割り当てます。
3.子ビューに渡す------> super.dispatchTouchEvent()を呼び出すデフォルトの実装では、onInterceptTouchEventを呼び出し、false onInterceptTouchEventを返します。その後、イベントはサブクラスに渡されます。
4.イベントは子ビューに渡されず、イベントは終了して渡され、イベントは親ビューのonTouchEventから開始してトレースバックを開始し、イベントは下から上に戻ってそれぞれのonTouchEventを実行します。コントロール-------> falseを返します;
注:ビューには子ビューがないため、onInterceptTouchEventで、イベントを子ビューに渡すかインターセプトするかを制御する必要はありません。したがって、ビューのイベント配布がsuper.dispatchTouchEvent()を呼び出すと、イベントはそのビューに渡されます。デフォルトでの独自のonTouchEvent処理(インターセプトと同等)ViewGroupのdispatchTouchEventイベント配布と比較して、DispatchTouchEvent()とonTouchEvent()のみがViewのイベント配布に参加するためにonInterceptTouchEvent()を必要としません。
この時点で、イベント配布の要約は完了です。
インタビュアー2:ビューレンダリングプロセス、またはビューレンダリングプロセス
この質問も古い質問ですが、BATと小規模なスタートアップの両方で頻繁に発生します。
次に、長い議論を避けるために、ビューの描画プロセスの概要を示します。以下の説明では、すべてを単純にします。
辛抱強く読んでいただければ幸いです。
ビューの描画プロセスは、ViewRoot.javaクラスのperformTraversals()関数で展開されます。
描画部分には、合計3つのステップが必要です。
メジャー()->レイアウト()->ドロー();
1.ビューサイズを再計算するかどうかを決定します(メジャー)
原則:
子Viewのように最上位の親Viewからview.measure()を再帰的に呼び出し、measureメソッドでonMeasure()を呼び出します。MeasureSpec
はViewの内部測定クラスです。測定仕様はintタイプです。値は次のように指定されます。上位2ビット仕様モードspecModeと下位30ビット仕様。サイズはspecSizeで構成されます。
specModeには3つの値があります:
MeasureSpec.UPSPECIFIED:親コンテナーには子コンテナーに対する制限がなく、子コンテナーは必要なだけ大きくすることができます。
MeasureSpec.EXACTLY:親コンテナーは子コンテナーのサイズを設定しており、子コンテナーが必要とするスペースの量に関係なく、子コンテナーはこれらの境界に従う必要があります。
MeasureSpec.AT_MOST:サブコンテナは、宣言されたサイズ内の任意のサイズにすることができます
-
Viewの測定方法は最終的なものであり、オーバーロードすることはできません。inMeasureをオーバーロードして、独自の測定ロジックを完成させることしかできません。
-
トップレベルのDecorViewのMeasureSpecは、ViewRootImplのgetRootMeasureSpecメソッドによって決定されます(LayoutParamsの幅と高さのパラメーターはMATCH_PARENT、specModeはEXACTLY、specSizeは物理画面サイズです)。
-
ViewGroupクラスは、親ビューと子ビューのサイズの計算を簡素化するために、measureChild、measureChild、およびmeasureChildWithMarginsメソッドを提供します。
-
ViewGroupのサブクラスである限り、MarginLayoutParamsを継承するためにLayoutParamsが必要です。そうでない場合、layout_marginパラメーターは使用できません。
-
ビューのレイアウトサイズは、親ビューと子ビューによって決定されます。
-
ビューのgetMeasuredWidth()メソッドとgetMeasuredHeight()メソッドを使用して、ビューの測定された幅と高さを取得します。有効な値を返すには、onMeasureプロセスの後にこれら2つのメソッドが呼び出されるようにする必要があります。
2.ビューの位置を再配布するかどうか(レイアウト)
原理:
レイアウトは、最上位の親ビューから子ビューにView.layoutメソッドを再帰的に呼び出すプロセスでもあります。親ビューは、子ビューによって取得されたレイアウトサイズとレイアウトパラメータに従って、子ビューを適切な位置に配置します。前のステップ。
-
View.layoutメソッドはオーバーロードでき、ViewGroup.layoutはfinalでオーバーロードできません。ViewGroup.onLayoutは抽象サブクラスであり、独自のロケーションロジックを実装するにはオーバーロードする必要があります。
-
測定が完了すると、測定後に各ビューのmeasuredWidthとmeasuredHeightが取得されます。レイアウト操作が完了すると、位置の割り当て後に各ビューのmLeft、mTop、mRight、およびmBottomが取得されます。これらの値は相対的です。親ビューに。
-
layout_XXXのすべてのレイアウト属性は親ビュー用です。ビューに親コンテナがない場合、layout_XXX属性は無意味です。
-
ビューのgetWidth()メソッドとgetHright()メソッドを使用して、ビューの測定された幅と高さを取得します。これら2つのメソッドがonLayoutプロセスの後にあることを確認する必要があります。
3.再描画(描画)するかどうか
原理:
描画プロセスは、ViewRootImplのperformTraversals()内にもディスパッチされます。呼び出しシーケンスはmeasure()とlayout()の後にあります。ここでのmViewは、ActivityのPhoneWindow.DecorViewです。ViewRootImplのコードはCanvasオブジェクトを作成し、Viewの描画を呼び出します。 ()特定の描画タスクを実行するメソッド。したがって、ViewGroupとViewのツリー再帰描画プロセスに戻ります。
-
ビューがViewGroupの場合、ビューに含まれるすべての子ビューを再帰的に描画する必要があります。
-
ビューはデフォルトでは何も描画せず、実際の描画は独自のサブクラスに実装されます
-
ビューの描画は、onDraw()メソッドによって渡されたCanvasクラスの助けを借りて実行されます
-
ビューアニメーションとビューグループアニメーションを区別します。前者はビュー自体のアニメーションであり、setAnimationを介して追加でき、後者はxmlレイアウトのlayoutAnimationプロパティを介して追加できます。
-
キャンバスクリッピング領域(各ビューの描画で渡されたキャンバス)を取得すると、パディングが自動的に処理されます。子ビューは、キャンバスを取得するためにこれらのロジックに注意を払う必要はありませんが、描画方法のみを考慮します。 。
-
デフォルトでは、子ビューのViewGroup.drawChildの描画順序は、子ビューが追加された順序と同じですが、ViewGroup.getChildDrawingOrder()をオーバーライドして別の順序を指定することもできます。
4. invalidate()
原理:
invalidateメソッドは、ビューツリー(つまり、drawメソッド)の再描画を要求します。ビューのサイズが変更されない場合、レイアウトプロセスは呼び出されず、「再描画が必要」なビューのみが描画されます。つまり、どのビュー(Viewはビューのみを描画し、ViewGroupはViewGroup全体を描画します)は、シリーズメソッドを無効にし、ビューを描画します。
-
invalidateメソッドを直接呼び出します。再度描画するように要求しますが、呼び出し元自体のみを描画します。
-
setSelectionメソッドをトリガーします。再度描画するように要求しますが、呼び出し元自体のみを描画します。
-
setVisibilityメソッドをトリガーします。ビューの視覚的状態がINVISIBLEからVISIBLEに変わると、invalidateメソッドが間接的に呼び出され、ビューが描画されます。INVISIBLE \ VISIBLEでビューの視覚状態がGONE状態に変換されると、requestLayoutメソッドとinvalidateメソッドが間接的に呼び出されます。同時に、ビューツリーのサイズが変更されたため、測定プロセスと描画プロセスは次のようになります。要求され、「再描画」ビューである必要がある描画のみ。
-
setEnabledメソッドをトリガーします。再描画を要求しますが、呼び出し元自体を含むビューは再描画されません。
-
requestFocusメソッドをトリガーします。「再描画が必要」なビューのみを描画するように、ビューツリーの描画プロセスを要求します。
例:アクティビティを作成するときは、表示するインターフェイスをsetContentViewメソッドを介してこのメソッドに渡す必要があります。このメソッドは、インターフェイスがaddView、次にaddViewを介してIDコンテンツを持つFrameLayout(ViewGroup)に追加されることを示します。メソッドinvalidate(true)をディスパッチして、トリガーされるViewRootImplクラスのperformTraversals()メソッドに通知することにより、これまでのところ、カスタマイズされたすべてのレイアウトを再帰的に描画します。
5.requestLayout()
原則: ViewのrequestLayoutの本質は、ViewRootImplに到達するまでレイヤーごとに渡すことです。その後、ViewRootImplのrequestLayoutメソッドの
requestLayout()メソッドがトリガーされます。requestLayout()メソッドは、測定プロセスとレイアウトプロセスを呼び出します。描画プロセスは呼び出されず、ビューは再描画されません。呼び出し元自体。
上記はビューレンダリングの全体的なプロセスです。ご不明な点がございましたら、訂正してください。
やっと
著者は現在深センにいて、JavaからAndroidに13年間開発しました。彼は小さな工場にいて、Huawei、OPPOなどにも行ってきました。彼は昨年4月にAliに入社しました。大きな工場にいた時、たくさんの人にインタビューをしました。ほとんどのジュニアおよびミドルレベルのAndroidエンジニアは、スキルを向上させたいと考えています。彼らは自分で成長することが多く、断片化されたシステムの学習効果は非効率的で、長く、無力です。
無意識のうちに数年前から成長していて、最初に出社したときはすごかったと思っていたのを覚えていますが、今は振り返ってみると無知です。理解すればするほど、理解が少なくなります。
あなたの知識が円であるならば、あなたの円が大きければ大きいほど、円の外側の世界は大きくなります。
言うまでもなく、誰もがコンセンサスを持っていると思います。業界がどうであれ、最も強力な人物は間違いなくピラミッドの終わりにいる人物です。したがって、優れたプログラマーになりたいのであれば、背を高くする必要があります。技術専門家になることは一夜にして問題ではなく、時間の浪費と技術の蓄積が必要です。
この点については、当時Androidの方向性を確立したときに、技術を体系的に学ぶ方法など、成長の道筋を整理し始めました。
ここでは、最後に、整理に1年以上かかった一連のAndroid学習リソースを共有します:Androidソースコード分析、Androidサードパーティライブラリソースコードノート、Androidアドバンストアーキテクト7トピック学習、BATインタビュー質問分析パッケージ、Androidマスタースタディノートなど。お待ちください。
これらのコンテンツは、フルバージョンが必要なすべての人、友人と無料で共有できます。すべてのコンテンツを表示するには、ここをクリックしてください。