Android 4.3上的“requestLayout()不正确地调用…”错误

我有一个简单的自定义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); } } 

从姜饼到JB 4.2都可以。 但是,当我在Android 4.3手机上显示自定义文本视图时,adb logcat充斥着以下消息。

 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 

我注意到,它确实减慢了一点UI。 任何想法为什么发生在4.3?

感谢你的帮助。

Related of "Android 4.3上的“requestLayout()不正确地调用…”错误"

我发现这个错误发生在我的应用程序中。 虽然在你提供的代码中没有发现这种情况(如果你在你的代码中的其他地方做了这个,也许会有所帮助),但希望能帮助其他人解决这个不可能的问题。

我有一行(当然不是我加的):

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

在我的应用程序中,我不需要任何监听器,所以删除整个块解决了这个问题。 对于那些需要这样的事情,请记住在布局已经改变之后(在这个callback中)移除监听器。

看一下Android的源代码 ,这个问题会更详细的描述一下:

requestLayout()在布局过程中被调用。 如果在请求视图中没有设置布局请求标志,则没有问题。 如果一些请求仍然未决,那么我们需要清除这些标记,并完成一个完整的请求/测量/布局过程来处理这种情况。

看来问题可能与Roboguice有关; 见问题#88 。 build议的解决scheme是使用@InjectView:

您现在可以在视图类中使用@InjectView。 在填充视图ala之后调用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); } } 

也许你应该考虑使用@InjectView注解将RoboGuice.injectMembers(context, this)移植到你的View对象的声明中。

我在我的自定义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()来直观地指示已检查的状态,在常规字体和粗体字体之间切换。 这些setTypeFace()调用导致警告。

为了解决这个问题,我在类构造函数中为Typeface创build了实例variables,并在稍后改变字体时使用它们,而不是每次调用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); } } 

这是一个相当具体的情况,但我惊喜地发现一个修复,也许别人是在相同的情况。

请检查天气任何视图的Id是否在同一活动上下文中重复。 我也得到相同的警告,我使用一个TextView重复循环相同的ID。 我每次都使用不同的ID来解决问题。

我遇到了同样的问题。 那是因为我试图用iOS的方式设置视图的位置。 你知道在iOS中设置视图的位置,通过设置视图的左上angular的值和宽度,高度。 但在Android中,它应该是(左,上,右,下)。 我对此非常重视。 当我跳到layout()定义中时,我阅读了方法的注释,然后我发现警告发生的原因。