Подтвердить что ты не робот

"requestLayout() неправильно вызван..." ошибка на Android 4.3

У меня есть простой Custom 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);
    }
}

Он отлично работает с Gingerbread через JB 4.2. Но logcat adb заливается следующими сообщениями, когда я показываю свой пользовательский текстовый просмотр на телефоне Android 4.3.

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

Я замечаю, что это немного замедляет пользовательский интерфейс. Любые идеи, почему это происходит на 4.3?

Цените свою помощь.

4b9b3361

Ответ 1

Я нашел, где эта ошибка возникает в моем приложении. Хотя появление этого не найдено в коде, который вы предоставили (это может помочь, если вы сделали это в другом месте вашего кода), он, надеюсь, поможет другим устранить эту проблему, невозможную для отслеживания.

У меня была строка (не добавленная мной, конечно):

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 layout.
    }
});

В моем приложении мне не нужен какой-либо прослушиватель, поэтому удаление всего этого блока устраняет эту проблему. Для тех, кому нужно что-то вроде этого, не забудьте удалить слушателя после изменения макета (внутри этого обратного вызова).

Ответ 2

В поисках источника Android эта проблема описана чуть подробнее:

requestLayout() вызывается во время компоновки. Если на запрашивающих представлениях не установлены флаги запроса компоновки, нет проблем. Если некоторые запросы все еще ожидаются, нам необходимо очистить эти флаги и выполнить полный запрос/мера/макет, чтобы справиться с этой ситуацией.

Похоже, что проблема может быть связана с Roboguice; см. issue # 88. Предлагаемое решение заключается в использовании @InjectView:

Теперь вы можете использовать @InjectView из класса представления. Просто вызовите Injector.injectMembers() после заполнения вашего представления, ala:

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);
    }
}

Возможно, вам стоит рассмотреть возможность переноса RoboGuice.injectMembers(context, this) на объявление вашего объекта View с помощью аннотации @InjectView.

Ответ 3

Я исправил эти предупреждения в своем пользовательском элементе 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"));
    }
}

Я визуально указываю проверенное состояние, вызывая setTypeFace() в текстовом элементе в моем представлении, переключая между регулярными и полужирным шрифтами. Эти вызовы setTypeFace() вызывали предупреждения.

Чтобы устранить проблему, я создал переменные экземпляра для Typeface в конструкторе класса и использовал их позже, когда вы меняете шрифт, а не вызываете 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);
    }
}

Это довольно специфический сценарий, но я был приятно удивлен, найдя исправление, и, возможно, кто-то еще находится в той же ситуации.

Ответ 4

Пожалуйста, проверьте погоду. Идентификатор любого вида повторяется внутри одного и того же контекста активности. Я также получал такое же предупреждение, я многократно использовал TextView цикл с тем же идентификатором. Я решил проблему, используя разные идентификаторы каждый раз.

Ответ 5

Я встретил ту же проблему. Это потому, что я пытался установить позицию представления в iOS. Вы знаете, что в iOS задано положение представления, задав значение верхнего левого представления, ширину и высоту. Но в Android это должно быть (левое, верхнее, правое, нижнее). Я уделял этому много внимания. Когда я перехожу в определение layout(), я читаю комментарий метода, затем выясняю, почему произошло предупреждение.