Android(requestLayout()调用不当)

古人已用三冬足,年少今开万卷余。这篇文章主要讲述Android:requestLayout()调用不当相关的知识,希望能为你提供帮助。
当我尝试在ListView中膨胀布局时发生以下错误:

requestLayout() improperly called by android.widget.TextView{...} during layout: running second layout pass

我试图在ListView内膨胀布局如下:
@Override public View getView(int position, View convertView, ViewGroup parent) { if(convertView == null){ LayoutInflater inflater = (LayoutInflater) musicActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = inflater.inflate(R.layout.list_item, parent, false); ... }else{...} }

膨胀的布局可以看起来像下面这样简单,并且仍然会产生错误
< TextView android:id="@+id/txt" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="@dimen/txt_size"/>

我已经研究了类似的问题,并没有找到解决方案似乎工作Question 1,Question 2,Question 3。
有谁知道导致此类错误的原因是什么?任何疑难解答建议更多的背景信息,这个ListView显示在Fragment内的ViewPager
UPDATE这是完整的XML布局(减去一堆属性),仍然会导致问题
< RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> < TextView android:id="@+id/txt1" android:layout_width="wrap_content" android:layout_height="wrap_content" /> < TextView android:id="@+id/txt2" android:layout_width="wrap_content" android:layout_height="wrap_content" /> < TextView android:id="@+id/txt3" android:layout_width="wrap_content" android:layout_height="wrap_content" /> < TextView android:id="@+id/txt4" android:layout_width="wrap_content" android:layout_height="wrap_content"/> < /RelativeLayout>

基于此,我认为XML本身不是问题,除非它与我使用ViewPager和Fragments这一事实有关
答案这个问题似乎是android实现中的一个错误,请参阅:https://code.google.com/p/android/issues/detail?id=75516
通过ListView在您的代码中激活ListView.setFastScrollEnabled(true)的快速滚动功能将触发此错误,您将开始看到
requestLayout()在布局期间由android.widget.TextView {...}不正确地调用:运行第二个布局传递
【Android(requestLayout()调用不当)】控制台中的消息。
这个bug必须在其中一个KitKat(4.4.x)更新中引入,因为我没有在最初的KitKat(4.4.0)版本中看到它。除了丑陋的控制台垃圾邮件与上面的调试消息,似乎没有其他影响(在某些情况下可能性能,我还没有测试)。
干杯
PS:这不是第一次快速滚动功能被窃听,例如https://code.google.com/p/android/issues/detail?id=63545,63545固定在KitKat 4.4.3但75516此后加速 - > 似乎是google的烦恼主题; -)
编辑2015年5月12日:
几分钟前我将Nexus 7更新为Android 5.1(之前运行的是5.0)并且在这个新版本中停止了这个问题。由于FastScroll指标的外观在5.1中也发生了变化,我认为google修复了这个问题,或者至少注释掉那些垃圾邮件控制台的丑陋线条......
75516和82461仍然“未解决”,但我想那些引用相同的问题,现在已经在5.1中解决了。
另一答案尝试从xml中取出textSize并在java代码中设置它。我认为这会导致它被布置两次。
另一答案有时您可能已经解决了问题,但它仍然保持相同的错误,因此您需要关闭visual studio然后从项目中删除所有bin和obj文件夹,然后从模拟器中卸载应用程序。然后walah !!一切都会好起来的
另一答案问题是,虽然适配器的方法getView()正在显示您的布局,但其他一些代码正试图访问此视图以显示它,从而导致冲突。
请注意,某些方法,也许你不关心(如setScale()setTypeFace())确实调用requestLayout(),所以在你的膨胀声明后你正在做的事情会很有趣。
另一答案对我来说,这个问题发生在setLayoutParams()电话上。正如here所说,解决方案是在looper上发布了一个runnable
另一答案我通过在XML中禁用ListView上的fastScroll来修复此问题。
< ListView android:id="@+id/mListview" android:layout_width="wrap_content" android:layout_height="match_parent"android:fastScrollEnabled="false" />

另一答案如果您使用ListView的某些第三方扩展,则可能会发生这种情况。用标准ListView替换它,并检查它是否仍然抛出错误。
我有类似的问题。请检查Android layout: running second layout pass和我的答案。
另一答案我在带有Genymotion的摩托罗拉X上遇到了与Kitkat 4.4.4相同的问题。在我的例子中,列表项是一个简单的CheckedTextView,错误发生在AppCompatCheckedTextView中。
作为一个正常的实现,我从XML布局文件中膨胀了项目,如下所示:
if (convertView == null) { convertView = inflater.inflate(R.layout.checkable_list_entry, parent, false); }

经过一番尝试后,我发现这与XML通胀有关。我不知道根本原因,但作为一个解决方案,我决定按代码对列表项进行膨胀,并按代码设置所有属性。
结果是这样的:
CheckedTextView view; if (convertView == null) { view = new CheckedTextView(parent.getContext()); view.setMinHeight(getResources().getDimensionPixelSize(R.dimen.default_touch_height)); if (Build.VERSION.SDK_INT > = Build.VERSION_CODES.M) { view.setTextAppearance(R.style.SectionEntry); } else { view.setTextAppearance(parent.getContext(), R.style.SectionEntry); } view.setBackgroundResource(R.drawable.form_element); view.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL); view.setLayoutParams(new AbsListView.LayoutParams(AbsListView.LayoutParams.MATCH_PARENT, AbsListView.LayoutParams.WRAP_CONTENT)); } else { view = (CheckedTextView) convertView; }

另一答案在我的情况下,此警告阻止按钮显示在API 21设备中。按钮可见性先前已设置为GONE。
我得到它的唯一解决方法是为API 21设置为INVISIBLE而不是GONE。这不是一个真正的解决方案,但它对我来说是可以接受的。
我只发布这个,因为它可以从某人有用。
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP) { theButton.setVisibility(View.INVISIBLE); } else { theButton.setVisibility(View.GONE); }

另一答案在我的情况下(三星Galaxy S4,API 21),这发生在带有EditTexts的ListView中。我有一个字段验证的监听器。就像是:
edit.setOnFocusChangeListener(new View.OnFocusChangeListener() { public void onFocusChange(View v, boolean hasFocus) { if (hasFocus) { error.setVisibility(View.INVISIBLE); error.setText(""); } else { String s = edit.getText().toString(); if (s.isEmpty()) { error.setText("Error 1"); } else if (s.length() < 2 || s.length() > 100) { error.setText("Error 2"); } error.setVisibility(View.VISIBLE); } } });

在其中一个EditTexts中设置焦点后,将调用上面的检查。之后,TextView将更改(TextView包含错误消息并位于EditText上)。将焦点设置为第二个或第三个EditText导致第一个EditText的永久请求并返回当前。应用程序在无限循环的请求中运行(焦点编辑文本1,非焦点编辑文本1,焦点3,非焦点3,焦点1等)。
我试图设置listView.setFastScrollEnabled(false)。我也尝试了一些像https://github.com/sephiroth74/HorizontalVariableListView/issues/93这样的元素的requestLayout(),没有机会。目前我用XML制作了固定宽度和高度的TextView:
< TextView android:id="@+id/error" android:layout_width="match_parent" (or "200dp", but not "wrap_content") android:layout_height="20dp" .../>

经过一些实验,我注意到20dp的高度可以用“wrap_content”代替。但是如果文本太长而不能分成2行,则应用程序会再次陷入无限循环。所以,android:singleLine="true"会有所帮助。它已被弃用,但令人惊讶的android:maxLines="1"android:lines="1"没有帮助,因为他们再次请求布局。最终我们有:
< TextView android:id="@+id/error" android:layout_width="match_parent" android:layout_height="wrap_content" android:singleLine="true" android:textColor="#f00" android:textSize="20sp" tools:text="Error message"/>

这不是一个好的解决方案,但至少它打破了无限循环。
另一答案我遇到了同一个警告日志的问题:
requestLayout() improperly called by android.support.v7.widget.AppCompatTextView {...} during layout: running second layout pass

我正在使用recyclerview并使用新数据更新它。
The only solution that worked for me is as below :步骤1)。删除当前数据:
public void removeAll() { items.clear(); //clear list notifyDataSetChanged(); }

第2步)。如果要使用新数据填充recyclerview,请先再次将新LayoutManager设置为recyclerview:
private void initRecycleView() { recyclerView.setHasFixedSize(true); recyclerView.setLayoutManager(new LinearLayoutManager(activity, LinearLayoutManager.VERTICAL, false)); }

步骤(3)。使用新数据更新recyclerview。例如 :
public void refreshData(List newItems) { this.items = newItems; notifyItemRangeChanged(0, items.size()); }


    推荐阅读