Android:requestLayout()调用不当

问题描述 投票:42回答:11

当我尝试在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

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 performance android-listview
11个回答
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此后加速 - >似乎是google的烦恼主题;-)

编辑2015年5月12日:

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

7551682461仍然“未解决”,但我想那些引用相同的问题,现在已经在5.1中解决了。


0
投票

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


0
投票

有时您可能已经解决了问题,但它仍然保持相同的错误,因此您需要关闭visual studio然后从项目中删除所有bin和obj文件夹,然后从模拟器中卸载应用程序。然后walah !!一切都会好起来的


16
投票

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

请注意,某些方法,也许你不关心(如setScale()setTypeFace())确实调用requestLayout(),所以在你的膨胀声明后你正在做的事情会很有趣。


7
投票

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


5
投票

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

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

    android:fastScrollEnabled="false"
/>

1
投票

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

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


1
投票

我在带有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;
}

1
投票

在我的情况下,此警告阻止按钮显示在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);
}

1
投票

在我的情况下(三星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"/>

这不是一个好的解决方案,但至少它打破了无限循环。


1
投票

我遇到了同一个警告日志的问题:

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());
}
© www.soinside.com 2019 - 2024. All rights reserved.