Android:requestLayout()调用不当

时间:2014-07-06 18:28:28

标签: android performance android-listview

当我尝试在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 1Question 2Question 3

有谁知道导致此类错误的原因是什么?任何疑难解答建议有关更多上下文,ListView显示在Fragment

内的ViewPager

更新

这是完整的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

的事实有关。

11 个答案:

答案 0 :(得分:41)

这个问题似乎是Android实现中的一个错误,请参阅:https://code.google.com/p/android/issues/detail?id=75516

通过ListView激活代码中ListView.setFastScrollEnabled(true)的快速滚动功能会触发此错误,您将开始看到

  

requestLayout()被android.widget.TextView {...}不正确地调用   布局期间:运行第二个布局传递

中的

消息。

这个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 - &gt;似乎是google的烦恼主题; - )

2015年5月12日编辑:

我几分钟前将Nexus 7更新为Android 5.1(之前运行的是5.0)并在此新版本中停止了这个问题。由于FastScroll指标的外观在5.1中也发生了变化,我认为谷歌解决了这个问题,或者至少注释掉那些垃圾邮件控制台的丑陋行......

75516&amp; 82461仍然“未解决”,但我猜这些问题引用了相同的问题,现在已经在5.1中解决了。

答案 1 :(得分:16)

问题是,当适配器的方法getView()显示您的布局时,其他一些代码正试图访问此视图以显示它,从而导致冲突。

请注意,某些可能无法处理的方法(例如setScale()setTypeFace())确实会调用requestLayout(),因此您正在做的事情会很有趣在你的膨胀声明之后。

答案 2 :(得分:6)

对我来说,这个问题是在setLayoutParams()电话时发生的。解决方案是在looper上发布了一个runnable,如here

所述

答案 3 :(得分:5)

我通过在XML中禁用ListView上的fastScroll来修复此问题。

<ListView
    android:id="@+id/mListview"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"

    android:fastScrollEnabled="false"
/>

答案 4 :(得分:1)

如果您正在使用ListView的某些第三方扩展,则可能会发生这种情况。用标准ListView替换它,并检查它是否仍然抛出错误。

我有类似的问题。请检查Android layout: running second layout pass和我的回答。

答案 5 :(得分:1)

我在使用Genymotion的Motorola 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;
}

答案 6 :(得分:1)

In my case (Samsung Galaxy S4, API 21) this happened in ListView with EditTexts. I have a listener for field validation. Something like:

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

After settinging focus in one of these EditTexts an above check is called. After that a TextView will change (the TextView contains an error message and lies over the EditText). Setting focus to the second or the third EditText led to permanent request of the first EditText and return to current. An applications runs in infinite loop of requests (focus edittext 1, unfocus edittext 1, focus 3, unfocus 3, focus 1, etc).

I tried to set listView.setFastScrollEnabled(false). Also I tried a requestLayout() of some elements like in https://github.com/sephiroth74/HorizontalVariableListView/issues/93 with no chances. Currently I made that TextView of fixed width and height in XML:

<TextView
    android:id="@+id/error"
    android:layout_width="match_parent" (or "200dp", but not "wrap_content")
    android:layout_height="20dp"
    .../>

After some experiments I noticed that a height of 20dp can be replaced with "wrap_content". But if a text is too long that divides into 2 lines, the application again catches in the infinite loop. So, android:singleLine="true" will help. It is deprecated, but amazingly android:maxLines="1" with android:lines="1" don't help as they again request layout. Eventually we have:

<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"/>

That's not a good solution, but at least it breaks the infinite loop.

答案 7 :(得分:1)

我在使用相同的警告日志时遇到了问题:

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

我正在使用recylcerview并打算用新数据进行更新。


唯一对我有用的解决方案如下:

步骤(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());
}

答案 8 :(得分:0)

尝试从xml中取出textSize并在Java代码中设置它。我认为这会导致它被布置两次。

答案 9 :(得分:0)

有时您可能已经解决了该问题,但仍然存在相同的错误,因此您需要关闭Visual Studio,然后从项目中删除所有bin和obj文件夹,然后从模拟器中卸载应用程序。然后哇!一切都会很好

答案 10 :(得分:0)

我解决了这样的问题:

    mHolder.txt_fword.setTextSize(22);
    mHolder.txt_farth.setTextSize(22);
    mHolder.txt_fdef.setTextSize(22);
    mHolder.txt_fdef2.setTextSize(22);
    mHolder.txt_frem.setTextSize(22);
    //if (fdef2.get(pos).equals("")) mHolder.txt_fdef2.setVisibility(View.GONE);        
    //if (frem.get(pos).equals("")) mHolder.txt_frem.setVisibility(View.GONE);

issue是.setVisibility(View.GONE); ,更改为.setVisibility(View.VISIBLE);