25

Mam proste niestandardowy TextView który ustawia niestandardową czcionkę w jego konstruktora jak poniższy kod„requestLayout() niewłaściwie nazywane przez ...” błędu na 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); 
    } 
} 

Współpracuje z Piernika przez JB 4.2 . Ale logcat adb jest zalewany następującymi komunikatami, gdy wyświetlam własny tekst na telefonie z Androidem 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 

Zauważam, że nieco spowalnia interfejs użytkownika. Jakieś pomysły, dlaczego tak się dzieje w 4.3?

Doceń swoją pomoc.

+0

Czy próbowałeś przenieść 'setTypeface()' i/lub 'setPaintFlags()' później w cyklu życia widoku, jak 'onFinishInflate()' czy coś? Domyślam się, że 'setTypeface()' wyzwala 'requestLayout()', ponieważ prawdopodobnie nie oczekiwali, że zostanie wywołana w konstruktorze widoku. – CommonsWare

+0

Próbowałem przenieść go do onFinishInflate(), które również nie pomogło. Widzę te wiadomości requestLayout() w dziennikach – Sanjay

+0

Czy jedynym celem MyTextView jest ustawienie niestandardowej czcionki? Tworzenie niestandardowego widoku, aby ustawić czcionkę cutom, nie jest dobrym rozwiązaniem. – GareginSargsyan

Odpowiedz

2

Looking into the Android source, ten problem jest opisany w nieco bardziej szczegółowo:

requestLayout() nazwano podczas układu. Jeśli w żądanych widokach nie są ustawione żadne flagi żądania układu, nie ma problemu. Jeśli niektóre żądania wciąż oczekują, musimy wyczyścić te flagi i wykonać pełną prośbę/miarę/przepustkę układu, aby poradzić sobie z tą sytuacją.

Wygląda na to, że problem może być związany z Roboguice; patrz issue #88. Sugerowanym rozwiązaniem jest użycie @InjectView:

Możesz teraz użyć @InjectView z wnętrza klasy widoku.

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

Być może należy rozważyć migrację RoboGuice.injectMembers(context, this) z deklaracją Pana zdaniem obiektu przy użyciu adnotacji @InjectView: wystarczy Injector.injectMembers() po tym, jak zaludnione Państwa zdaniem, Ala zadzwonić.

+2

W ogóle nie używam Roboguice, tylko ustawienie kroju czcionki w moim onCreate. Jakieś przemyślenia na temat tego, dlaczego tak się stanie w moim przypadku lub w przypadku jakichkolwiek obejść? –

+0

[Sprawdzanie źródła 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()' rzeczywiście wywołuje 'requestLayout()', co ma sens, ponieważ wymiary mogą wymagać zmiany. Nie jestem pewien, dlaczego może to powodować sprzeczne przekazywanie układu. Być może mógłbyś spróbować uprościć swój układ? Jestem na to zakłopotany. –

6

Znalazłem błąd w mojej aplikacji. Chociaż tego wystąpienia nie ma w podanym kodzie (może to pomóc, jeśli zrobiłeś to gdzie indziej w twoim kodzie), to mam nadzieję, że pomożemy innym naprawić ten niemożliwy do wykrycia problem.

miałem linię (nie dodaną przeze mnie, oczywiście):

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

W mojej aplikacji, nie potrzeba żadnego słuchacza, dlatego usuwając cały ten blok stałe ten problem. Dla tych, którzy potrzebują czegoś takiego, pamiętaj o usunięciu słuchacza po zmianie układu (wewnątrz tego wywołania zwrotnego).

0

Proszę sprawdzić, czy identyfikator dowolnego widoku powtarza się w tym samym kontekście aktywności. Otrzymałem również to samo ostrzeżenie, wielokrotnie korzystałem z TextView z tym samym identyfikatorem. Rozwiązałem problem, używając za każdym razem różnych identyfikatorów.

+0

Mam taki sam problem z widokami tekstu, ale nie mogę zmienić identyfikatora dla każdego! czy możesz napisać jakiś kod? – Smile2Life

1

Naprawiłem te ostrzeżenia w moim niestandardowym obiekcie ListView (podklasa LinearLayout). Ta klasa implementuje Checkable i ma setChecked(boolean checked) metody, która jest wywoływana w celu wskazania, czy element jest sprawdzana:

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

I wizualnie wskazać sprawdzenia stanu wywołując setTypeFace() na TextView moim zdaniem, przełączanie pomiędzy regularnymi i odważnych krojów . Te wywołania setTypeFace() powodowały ostrzeżenia.

Aby rozwiązać ten problem, stworzyłem zmiennych instancji dla Typeface S w konstruktorze klasy i wykorzystywali je później, przy zmianie czcionki, zamiast wywoływania Typeface.createFromAsset(...) za każdym razem:

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

Jest to dość specyficzny scenariusz, ale byłem mile zaskoczony, gdy znalazłem poprawkę i być może ktoś inny znalazł się w tej samej sytuacji.

0

Spotkałem ten sam problem. To dlatego, że próbowałem ustawić pozycję widoku w systemie iOS. W ustawieniach systemu iOS ustaw pozycję widoku, ustawiając lewą najwyższą wartość widoku i szerokość, wysokość. Ale w systemie Android powinien być (lewy, górny, prawy, dolny). Zwróciłem na to uwagę. Kiedy wskakuję do definicji layout(), czytam komentarz metody, a następnie dowiaduję się, dlaczego nastąpiło ostrzeżenie.

Powiązane problemy