Android RecyclerView创建并绑定数据集更改的所有视图

Android RecyclerView创建并绑定数据集更改的所有视图,android,android-recyclerview,Android,Android Recyclerview,我有一个非常大的应用程序,我几乎在所有地方都使用了RecylClerView, 我知道如何实现RecyclerViews,我从来没有遇到过任何问题! 但是最近我在一个RV上遇到了一个非常严重的延迟,(让我向你保证我的bindview方法非常好,我在asynctasks中加载了所有的图像…),这是在第一次显示RV时我得到了一个ANR 经过数小时的调试,我发现每次数据集更改(notifyDataset()),包括RV第一次填充时,都会创建并绑定所有视图(是的,调用onCreateView()的次数是

我有一个非常大的应用程序,我几乎在所有地方都使用了RecylClerView, 我知道如何实现RecyclerViews,我从来没有遇到过任何问题! 但是最近我在一个RV上遇到了一个非常严重的延迟,(让我向你保证我的bindview方法非常好,我在asynctasks中加载了所有的图像…),这是在第一次显示RV时我得到了一个ANR

经过数小时的调试,我发现每次数据集更改(notifyDataset()),包括RV第一次填充时,都会创建并绑定所有视图(是的,调用onCreateView()的次数是200次,这与RecyclerView的原理正好相反!) 一旦创建并绑定了所有视图,应用程序就会开始正常运行,我的意思是不再需要onCreateView()和onBindView()调用,没有任何延迟

我知道很难找到原因,但我想可能有一个明显的背景或。。。这导致了这一点或一些过去的经验,所以用户可以帮助我


编辑 显然,原因在于我的XML以及我如何制作RV来填充自由区域,因为当我将其高度设置为指定值(例如400 dp)时,一切正常,但如果我使用LinearLayout和
layout\u weight
或使用RelativeLayout(设置在对齐的顶部元素下方和对齐的底部元素上方)重现问题

所以我能说的是,当需要动态计算RV的高度时,就会出现这个问题,我猜它会创建所有的子对象来计算RV的高度,这显然是支持库中的一个错误(com.android.support:recyclerview-v7:23.4.0当时)

有人有解决办法吗? 或者你能告诉我我的错误吗


解决方案 为未来的谷歌人

似乎解决方案是使用
setAutoMeasureEnabled(false)。
此方法已在支持库的
23.2.0
版本中引入,并有助于将包装内容用作RV项目的布局参数,
不管怎样,我用这个方法克服了我的问题,并且我对我的项目高度使用了wrap_内容,没有问题,

onBindViewHolder就是将被调用来显示视图的那个。第一次在BindViewHolder()上设置适配器时,不会被调用200次。它将仅对可见的项目数进行调用。例如,如果有4个项目可见,onBindViewHolder将被调用4次,因为滚动onBindViewHolder将被调用,具体取决于需要绘制的项目数量

如果某些数据正在更改,并且您使用NOTIFYDATASETCHANGE(),则将重新绘制所有视图。如果要插入元素并希望刷新适配器,请使用

adapter.notifyItemInserted(position);
或删除

adapter.notifyItemRemoved(positionOfObject);
adapter.notifyItemRangeChanged(positionOfObject, arrayList.size());

更有效的是

回收器视图应该只为创建时可见的行调用OnCreateViewHolder(…)和OnBindViewHolder(…)。如果需要在加载图像或类似内容时刷新列表中的行,则应避免使用notifyDataSetChanged()。相反,您可以使用invalidateChild(…)方法之一。要找到要使其无效的正确子级,可以使用findViewHolderForAdapterPosition(int-position)。另一种方法是使用适配器的notifyItemChanged(int-position)方法。

我遇到了类似的问题:onBindViewHolder调用了所有数据条目,即使我希望只为可见的条目调用它


我发现这是因为我的视图持有者的大小是用包装内容定义的,并且内容是我用图像加载库异步加载的图像,所以当视图持有者最初绑定时,它的大小是0 px,并且用户可以看到所有的持有者。只有在图像加载完成后,才会调整viewholdera和viewholdera的大小。但那个时候,viewholder已经被绑定了。

我也面临着类似的问题,运行在安卓5上的设备在列表中添加了所有元素,以及它的创建问题


当我更改recyclerview时,我将其设置为包裹内容的高度,并将其固定为平稳工作的高度。

我遇到了类似的问题,我在ViewPager中使用了recyclerview。将项设置为适配器时,RecyclerView也绑定了两次所有视图。我在基本ViewPager类中发现了问题。我放了几行代码,根据它的孩子动态计算ViewPager的高度。当我删除该代码时,RecyclerView工作正常。代码如下

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int mode = MeasureSpec.getMode(heightMeasureSpec);
    // Unspecified means that the ViewPager is in a ScrollView WRAP_CONTENT.
    // At Most means that the ViewPager is not in a ScrollView WRAP_CONTENT.
    if (mode == MeasureSpec.UNSPECIFIED || mode == MeasureSpec.AT_MOST) {
        // super has to be called in the beginning so the child views can be initialized.
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int height = 0;
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
            int h = child.getMeasuredHeight();
            if (h > height) height = h;
        }
        heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
    }
    // super has to be called again so the new specs are treated as exact measurements
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@覆盖
测量时的保护空隙(内部宽度测量等级、内部高度测量等级){
int mode=MeasureSpec.getMode(heightMeasureSpec);
//未指定表示ViewPager位于ScrollView内容中。
//最多意味着ViewPager不在ScrollView内容中。
if(mode==MeasureSpec.UNSPECIFIED | | mode==MeasureSpec.AT_){
//必须在开始时调用super,以便可以初始化子视图。
超级测量(宽度测量、高度测量);
整数高度=0;
对于(int i=0;i高度)高度=h;
}
heightMeasureSpec=MeasureSpec.MakeMasureSpec(高度,精确测量);
}
//必须再次调用super,以便将新规格视为精确测量
超级测量(宽度测量、高度测量);
}

当然,你是对的,问题是RV的性能不符合预期!我刚才提到了
notifyDatasetChanged()
,因为我看到这是在重新创建问题,但第一个问题仍然是在一开始就创建和绑定所有项。您是否在onBindViewHolder中放置了日志语句来检查它?是的,这就是我在onCreateViewHolde中发现的