web-dev-qa-db-ja.com

Android 4.3での「requestLayout()が不適切に呼び出されました...」エラー

以下のコードのように、コンストラクタにカスタムフォントを設定する単純なカスタムTextViewがあります。

public class MyTextView extends TextView {

    @Inject CustomTypeface customTypeface;

    public MyTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        RoboGuice.injectMembers(context, this);
        setTypeface(customTypeface.getTypeface(context, attrs));
        setPaintFlags(getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG);
    }
}

ジンジャーブレッドからJB 4.2まで正常に動作します。しかし、Android 4.3電話でカスタムテキストビューを表示すると、adb logcatは次のメッセージで溢れます。

10-05 16:09:15.225: WARN/View(9864): requestLayout() improperly called by com.cmp.views.MyTextView{42441b00 V.ED.... ......ID 18,218-456,270 #7f060085 app:id/summary} during layout: running second layout pass
10-05 16:09:15.225: WARN/View(9864): requestLayout() improperly called by com.cmp.views.MyTextView{423753d0 V.ED.... ......ID 26,176-742,278 #7f060085 app:id/summary} during layout: running second layout pass

私は、UIが少し遅くなることに気づきました。それが4.3で起こっている理由は何ですか?

あなたの助けに感謝。

26
Sanjay

このバグがアプリのどこで発生するかを見つけました。これは、指定したコードには含まれていませんが(コードの別の場所で行った場合に役立つことがあります)、他の人がこの追跡不可能な問題を修正するのに役立つでしょう。

(もちろん、自分では追加しませんでした)行がありました:

myView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
    @Override
    public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
        //this would then make a call to update another view's layout.
    }
});

私のアプリでは、リスナーは必要なかったので、このブロック全体を削除すると、この問題が修正されました。このようなものが必要な場合は、レイアウトが変更された後に(このコールバック内で)リスナーを削除することを忘れないでください。

6
Phil

Androidソース を調べて、この問題についてもう少し詳しく説明します。

requestLayout()がレイアウト中に呼び出されました。要求しているビューにレイアウト要求フラグが設定されていない場合、問題はありません。一部のリクエストがまだ保留中の場合は、これらのフラグをクリアし、リクエスト/測定/レイアウトパスをすべて実行して、この状況を処理する必要があります。

問題はRoboguiceに関連している可能性があります。 issue#88 を参照してください。 @InjectViewを使用することをお勧めします。

これで、ビュークラス内から@InjectViewを使用できます。ビューalaにデータを入力したら、Injector.injectMembers()を呼び出します。

_public class InjectedView extends FrameLayout {

    @InjectView(R.id.view1) View v;

    public InjectedView(Context context) {
        super(context);
        final View child = new View(context);
        child.setId(R.id.view1);
        addView(child);

        RoboGuice.getInjector(context).injectMembers(this);
    }
}
_

おそらく、@ InjectViewアノテーションを使用して、RoboGuice.injectMembers(context, this)をViewオブジェクトの宣言に移行することを検討する必要があります。

2
Paul Lammertsma

カスタムListViewアイテム(LinearLayoutサブクラス)でこれらの警告を修正しました。このクラスはCheckableを実装し、アイテムがチェックされているかどうかを示すために呼び出されるsetChecked(boolean checked)メソッドを持っています。

_@Override
public void setChecked(boolean checked) {
    mChecked = checked;
    TextView textView = (TextView)this.findViewById(R.id.drawer_list_item_title_text_view);
    if(mChecked) {
        textView.setTypeface(Typeface.createFromAsset(getContext().getAssets(), "font/Andada-Bold.ttf"));
    }
    else {
        textView.setTypeface(Typeface.createFromAsset(getContext().getAssets(), "font/Andada-Regular.ttf"));
    }
}
_

私のビューのtextViewでsetTypeFace()を呼び出し、通常の書体と太字の書体を切り替えて、チェックされた状態を視覚的に示します。これらのsetTypeFace()呼び出しが警告の原因でした。

問題を解決するために、クラスコンストラクターでTypefacesのインスタンス変数を作成し、後で毎回Typeface.createFromAsset(...)を呼び出すのではなく、タイプフェイスを変更するときにそれらを使用しました。

_private Typeface mBoldTypeface;
private Typeface mRegularTypeface;

public DrawerView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initTypefaces();
}

private void initTypefaces() {
        this.mBoldTypeface = Typeface.createFromAsset(getContext().getAssets(), "font/Andada-Bold.ttf");
        this.mRegularTypeface = Typeface.createFromAsset(getContext().getAssets(), "font/Andada-Regular.ttf");
}

@Override
public void setChecked(boolean checked) {
    mChecked = checked;
    TextView textView = (TextView)this.findViewById(R.id.drawer_list_item_title_text_view);
    if(mChecked) {
        textView.setTypeface(mBoldTypeface);
    }
    else {
        textView.setTypeface(mRegularTypeface);
    }
}
_

これはかなり具体的なシナリオですが、修正を見つけてうれしく思いました。おそらく他の誰かが同じ状況にいるのかもしれません。

1
kurteous

同じ問題に遭遇しました。これは、iOSの方法でビューの位置を設定しようとしたためです。 iOSでは、ビューの左上の値と幅、高さを設定してビューの位置を設定します。しかし、Androidでは(左、上、右、下)でなければなりません。私はこれに多くの注意を払いました。 layout()定義にジャンプすると、メソッドのコメントが読み込まれ、警告が発生した理由がわかります。

0
Bruce Lee

同じアクティビティコンテキスト内でビューのIDが繰り返されている天気を確認してください。私も同じ警告を受けていました。TextViewを繰り返し使用していて、同じIDのループがありました。毎回異なるIDを使用して問題を解決しました。

0
sravan kumar