25

У меня есть простой пользовательский TextView, который устанавливает специальный шрифт в его конструктор как код ниже«requestLayout() неправильно называют ...» ошибки на Android 4.3

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?

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

+0

Вы пытались переместить 'setTypeface()' и/или 'setPaintFlags()' позже в жизненном цикле представления, например 'onFinishInflate()' или что-то еще? Я предполагаю, что 'setTypeface()' запускает 'requestLayout()', поскольку они, вероятно, не ожидали, что он будет вызван в конструкторе представления. – CommonsWare

+0

Я попытался переместить его в onFinishInflate(), что тоже не помогло. Я вижу те запросы requestLayout() в журналах – Sanjay

+0

Является ли единственным назначением MyTextView настраиваемым шрифтом? Создание настраиваемого представления для установки шрифта cutom не является хорошим решением. – GareginSargsyan

ответ

2

Looking into the Android source, эта проблема описана в немного более подробно:

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

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

Теперь вы можете использовать @InjectView из класса представления. Просто позвоните 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); 
    } 
} 

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

+2

Я вообще не использую Roboguice, просто устанавливаю Typeface в свой onCreate. Любые мысли о том, почему это произойдет в моем случае, или какие-либо обходные пути? –

+0

[Проверка источника AOSP] (http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.3_r1/android/widget/TextView.java#TextView.setTypeface % 28android.graphics.Typeface% 29), 'setTypeface()' действительно вызывает 'requestLayout()', что имеет смысл, поскольку размеры могут нуждаться в изменении. Я не уверен, почему это может вызвать противоречивые макеты. Возможно, вы могли бы попытаться упростить свой макет? Я в тупике. –

6

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

У меня была линия (не добавил я, конечно):

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

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

0

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

+0

У меня такая же проблема с текстовыми представлениями, но я не могу изменить идентификатор для каждого! можете ли вы опубликовать код? – Smile2Life

1

Я исправил эти предупреждения в своем обычном 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() на TextView, на мой взгляд, переключаясь между регулярными и жирными шрифтами , Эти вызовы 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); 
    } 
} 

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

0

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

Смежные вопросы