web-dev-qa-db-ja.com

ビューのmeasure()が呼び出される原因

私のアプリケーションでは、ViewのonMeasure()オーバーライドの1つに無限ループがあります。 onMeasureのブレークポイントから始まるソースコードをデバッグすると、ViewRootによって呼び出されるPhoneWindow $ DecorViewのmeasure()(View Hierarchyの最上位クラス)までスタックトレースまでトレースできます。 .performTraversals()。ここからステップオーバーを続けると、最終的にはLooper.loop()クラスのメッセージによってPhoneWindow $ DecorViewのmeasure()が再度呼び出されます。無効化のように、再測定が必要なメッセージがキューに入れられていると思います。

私の質問は、メジャーコールがビューで発生する必要があるトリガーは何ですか?

レイアウト/測定/描画プロセスの私の理解から、これは特定のビューでinvalidate()メソッドが呼び出されたときにのみ発生し、無効化されたビューとすべてのビューのレイアウト/測定/描画パスを実行しますその子。どういうわけか、ビュー階層の一番上のビューが無効になっていると思います。

しかし、私は明示的に無効化の呼び出しごとにブレークポイントを設定しており、無限の方法で無効化を呼び出していません。だからそうだとは思わない。測定パスをトリガーする別の方法はありますか?内部的に何かがこれを引き起こしている可能性がありますか?無限の無効化は何もないと思った後、私は一種のアイデアから外れています。

43
C Nick

カスタムビューのメジャーパスをトリガーするには、requestLayout()メソッドを呼び出す必要があります。たとえば、Viewを拡張するカスタムビューを実装し、TextViewのように動作する場合、次のようなsetTextメソッドを記述できます。

/**
 * Sets the string value of the view.
 * @param text the string to write
 */
public void setText(String text) {
    this.text = text;

            //calculates the new text width
    textWidth = mTextPaint.measureText(text);

    //force re-calculating the layout dimension and the redraw of the view
    requestLayout();
    invalidate();
}
81
moondroid

さて、ビューのコンテンツを変更する場合、最終的にinvalidate()を呼び出す必要があります。たとえば、「テキスト1」というテキストを持つTextViewがあります。次に、同じTextViewのテキストを「Text 2」に変更します。ここでも、invalidateが呼び出されます。

そのため、基本的に、ビューで何かが変更されると、多くの場合、無効化メソッドが呼び出され、対応するmeasure()の呼び出しが期待されます。

たとえば、TextViewのソースコードを見てください。 http://www.google.com/codesearch#uX1GffpyOZk/core/Java/Android/widget/TextView.Java&q=TextView%20package:Android&type=cs

無効化呼び出しの数をカウントします。かなりあります。

1
Kumar Bibek