I have a simple Custom TextView that sets custom font in its constructor like the code below
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);
}
}
It works fine from Gingerbread through JB 4.2. But the adb logcat is flooded with the following messages when I show my custom textview on Android 4.3 phone.
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
I notice, it does slow down UI a bit. Any ideas why it's happening on 4.3?
Appreciate your help.
I found where this bug occurs in my app. Although occurrence of this is not found in the code you provided (it may help if you have done this elsewhere in your code), it will hopefully help others fix this impossible-to-trace problem.
I had a line (not added by me, of course):
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.
}
});
In my app, I did not need any listener, so removing this entire block fixed this problem. For those that need something like this, remember to remove the listener after the layout has changed (inside of this callback).
Looking into the Android source, this problem is described in a little more detail:
requestLayout()
was called during layout. If no layout-request flags are set on the requesting views, there is no problem. If some requests are still pending, then we need to clear those flags and do a full request/measure/layout pass to handle this situation.
It appears that the problem may be related to Roboguice; see issue #88. The suggested solution there is to use @InjectView:
You can now use @InjectView from inside a view class. Just call Injector.injectMembers() after you've populated your view, 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); } }
Perhaps you should consider migrating RoboGuice.injectMembers(context, this)
to the declaration of your View object using the @InjectView annotation.
I fixed these warnings in my custom ListView
item (LinearLayout
subclass). This class implements Checkable
, and has a setChecked(boolean checked)
method that is called to indicate whether the item is 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"));
}
}
I visually indicate the checked state by calling setTypeFace()
on a textView in my view, toggling between regular and bold typefaces. These setTypeFace()
calls were causing the warnings.
To fix the problem, I created instance variables for the Typeface
s in the class constructor and used them later, when changing the typeface, rather than calling Typeface.createFromAsset(...)
every time:
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);
}
}
This is a pretty specific scenario, but I was pleasantly surprised to find a fix and maybe someone else is in the same situation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With