"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?
Цените свою помощь.
Ответы
Ответ 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()
, я читаю комментарий метода, затем выясняю, почему произошло предупреждение.