25

Ho una semplice TextView personalizzato che imposta carattere personalizzato nel suo costruttore, come il codice qui sotto"requestLayout() impropriamente chiamato da ..." errore su 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); 
    } 
} 

Funziona bene da Gingerbread attraverso JB 4.2 . Ma il logbat adb è inondato con i seguenti messaggi quando mostro la mia vista testuale personalizzata su telefono 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 

Noto che rallenta l'interfaccia utente un po '. Qualche idea sul perché sta accadendo su 4.3?

Apprezzo il tuo aiuto.

+0

Hai provato a spostare 'setTypeface()' e/o 'setPaintFlags()' più avanti nel ciclo di vita della vista, come 'onFinishInflate()' o qualcosa del genere? La mia ipotesi è che 'setTypeface()' stia attivando un 'requestLayout()', poiché probabilmente non si aspettavano che venisse chiamato in un costruttore di viste. – CommonsWare

+0

Ho provato a spostarlo su onFinishInflate(), che non ha aiutato neanche. Vedo quei messaggi requestLayout() nei registri – Sanjay

+0

L'unico scopo del MyTextView è impostare un carattere personalizzato? Creare una vista personalizzata per impostare un font non è una buona soluzione. – GareginSargsyan

risposta

2

Looking into the Android source, questo problema è descritto in maggiore dettaglio:

requestLayout() stato chiamato durante il layout. Se nessun flag di richiesta di layout è impostato sulle viste richieste, non ci sono problemi. Se alcune richieste sono ancora in sospeso, è necessario cancellare tali flag ed eseguire un passaggio completo di richiesta/misura/layout per gestire questa situazione.

Sembra che il problema possa essere correlato a Roboguice; vedi issue #88. La soluzione suggerita è quella di utilizzare @InjectView:

Ora è possibile utilizzare @InjectView all'interno di una classe di visualizzazione. Basta chiamare Injector.injectMembers() dopo aver popolato la vista, 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); 
    } 
} 

forse si dovrebbe prendere in considerazione la migrazione RoboGuice.injectMembers(context, this) alla dichiarazione del vostro oggetto View usando l'annotazione @InjectView.

+2

Non sto utilizzando affatto Roboguice, basta impostare un carattere tipografico nel mio onCreate. Qualche idea sul perché ciò accadrebbe nel mio caso, o qualche soluzione alternativa? –

+0

[Ispezione della sorgente 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()' invoca 'requestLayout()', il che ha senso in quanto le dimensioni potrebbero aver bisogno di essere cambiate. Non sono sicuro del motivo per cui ciò potrebbe causare passaggi di layout in conflitto. Forse potresti provare a semplificare il layout? Sono perplesso su questo. –

6

Ho trovato dove si verifica questo errore nella mia app. Sebbene il verificarsi di questo non si trovi nel codice che hai fornito (potrebbe essere d'aiuto se lo hai fatto altrove nel tuo codice), si spera che possa aiutare gli altri a risolvere questo problema impossibile da tracciare.

ho avuto una linea (non da me inserito, ovviamente):

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

Nella mia app, non ho bisogno di alcun ascoltatore, in modo da rimuovere l'intero blocco risolto questo problema. Per coloro che hanno bisogno di qualcosa di simile, ricordarsi di rimuovere il listener dopo che il layout è cambiato (all'interno di questo callback).

0

Si prega di verificare il tempo l'Id di qualsiasi vista si ripete all'interno dello stesso contesto di attività. Avevo anche lo stesso avvertimento, stavo usando un TextView ripetutamente un loop con lo stesso id. Ho risolto il problema utilizzando id diversi ogni volta.

+0

Ho lo stesso problema con le visualizzazioni di testo, ma non posso modificare l'id per ognuna! puoi pubblicare del codice? – Smile2Life

1

Ho corretto questi avvisi nel mio articolo personalizzato ListView sottoclasse (LinearLayout). Questa classe implementa Checkable, e ha un metodo di setChecked(boolean checked) che viene chiamato per indicare se l'elemento è controllato:

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

indico visivamente lo stato controllato chiamando setTypeFace() su un textView a mio avviso, commutazione tra caratteri regolari e in grassetto . Queste chiamate setTypeFace() stavano causando gli avvisi.

Per risolvere il problema, ho creato le variabili di istanza per i Typeface s nel costruttore della classe e li hanno usati in seguito, quando si cambia il tipo di carattere, piuttosto che chiamare Typeface.createFromAsset(...) ogni volta:

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

Questa è una bella specifica scenario, ma sono stato piacevolmente sorpreso di trovare una soluzione e forse qualcun altro si trova nella stessa situazione.

0

Ho incontrato lo stesso problema. Questo perché stavo cercando di impostare la posizione di una vista in modo iOS. Sai in iOS impostare la posizione di una vista impostando il valore superiore sinistro della vista e la larghezza, l'altezza. Ma in Android dovrebbe essere (a sinistra, in alto, a destra, in basso). Ho fatto molta attenzione a questo. Quando salgo nella definizione layout(), ho letto il commento del metodo, quindi ho scoperto perché l'avviso è avvenuto.

Problemi correlati