RecyclerView.onBindViewHolder 只调用一次
Posted
技术标签:
【中文标题】RecyclerView.onBindViewHolder 只调用一次【英文标题】:RecyclerView.onBindViewHolder called only once 【发布时间】:2016-08-18 19:31:54 【问题描述】:经过数小时的研究,我终于咨询了官方帮助。
我有一个完美运行的 RecyclerView.Adapter 和 RecyclerView.ViewHolders。但是由于某些我不明白的原因,没有正确调用 RecyclerView.Adapter.onBindViewHolder。
private class AttendeeAdapter extends RecyclerView.Adapter<AttendeeHolder>
/*FIELDS*/
private List<Attendee> mAttendeeList;
/*CONSTRUCTORS*/
public AttendeeAdapter(List<Attendee> attendees)
mAttendeeList = attendees;
//Log.i(TAG, "AttendeeAdapter size: " + getItemCount());
根据日志消息(项目按预期计为列表的大小),我假设 AttendeeAdapter 已正确实例化。
所以我希望 onBindViewHolder(VH, int) 方法的调用次数与 List 的大小一样多,但事实并非如此。该方法只调用一次!
/*METHODS*/
@Override
public AttendeeHolder onCreateViewHolder(ViewGroup parent, int viewType)
LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
View itemView = layoutInflater.inflate(R.layout.list_attendee, parent, false);
return new AttendeeHolder(itemView);
@Override
public void onBindViewHolder(AttendeeHolder holder, int position)
Attendee attendee = mAttendeeList.get(position);
holder.bindAttendee(attendee, position);
Log.i(TAG, "Binding ViewHolder #" + position);
/* Binding ViewHolder #0 and that's it */
@Override
public int getItemCount()
return mAttendeeList.size();
我的 AttendeeHolder(扩展 RecyclerView.ViewHolder)如下:
private class AttendeeHolder extends RecyclerView.ViewHolder
/*FIELDS*/
private EditText mAttendeeNameEditText;
private Attendee mAttendee;
/*CONSTRUCTOR*/
public AttendeeHolder(View itemView)
super(itemView);
mAttendeeNameEditText = (EditText) itemView.findViewById(R.id.edit_text_list_item);
mAmountEditTextList = new ArrayList<>(eventMaxCount);
/*METHODS*/
public void bindAttendee(Attendee attendee, final int position)
mAttendee = attendee;
String attendeeName = mAttendee.getName();
// Set the name to the EditText if a name has already been set
if (attendeeName != null)
mAttendeeNameEditText.setText(attendeeName);
并在主代码中实现为
List<Attendee> attendees = AttendeeLab.get().getAttendeeList();
mAttendeeAdapter = new AttendeeAdapter(attendees);
mAmountRecyclerView.setAdapter(mAttendeeAdapter);
我猜代码可以工作(我想我没有做任何更改),但可能没有正确设置 gradle 依赖项。那是我尝试将 recyclerview-v7:23.3.0 修改为 recyclerview-v7:23.1.0 或其他任何东西的地方(它们都不起作用)。
dependencies
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.3.0'
compile 'com.android.support:design:23.3.0'
compile 'com.android.support:support-v4:23.3.0'
compile 'com.android.support:recyclerview-v7:23.1.2'
任何帮助或评论将不胜感激。我希望我能在几个小时后告别头痛。
【问题讨论】:
不确定这是否意味着什么 - 但是您如何访问您的AttendeeHolder
,因为它具有私有访问权限并且它不位于您的 AttendeeAdapter
..?此外,对您的build.gradle
中的支持包使用相同的版本。
ViewHolder 和 Adapter 是主代码中的内部类,因此可以访问。
你解决了这个问题! RecyclerViews 使用相同(旧)版本的支持包正常工作,即 v7:23.1.2。很抱歉,我对 Gradle 的工作原理了解甚少,但它应该以这种方式工作吗?如果我坚持将 RecyclerViews 与新的 recyclerview-v7:23.3.0 库一起使用怎么办?
【参考方案1】:
在我的情况下,recyclerview 的单项布局的根布局(约束布局)高度设置为 match_parent 而不是 'wrap_content',将其更改为 'wrap_content' 和问题是固定的
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_
android:layout_>
<androidx.cardview.widget.CardView
android:layout_
android:layout_
tools:ignore="MissingConstraints">
<TextView
android:id="@+id/tv_city_name"
android:layout_
android:layout_
android:layout_margin="8dp"
android:gravity="center"
android:text="@location.name"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:typeface="serif" />
</androidx.cardview.widget.CardView>
【讨论】:
【参考方案2】:就我而言,我必须覆盖getItemId()
。当我向适配器添加不同的项目时,它们具有相同 id
。 onBindViewHolder
在滚动时停止调用。所以,我从
override fun getItemId(position: Int): Long = list[position].id.toLong()
到
override fun getItemId(position: Int): Long = position.toLong()
适配器还包含以下设置:
override fun getItemCount(): Int = list.size
override fun getItemViewType(position: Int): Int = list[position].viewType
this.setHasStableIds(true)
最好使用带有 unique id
s 的集合。
【讨论】:
【参考方案3】:在我遇到的一个案例中,我的回收站视图只能水平滚动,不能垂直滚动。
【讨论】:
【参考方案4】:还要检查您是否将 RecyclerView 本身的高度设置为 android:layout_height="wrap_content"
或 android:layout_height="match_parent"
。在这两种情况下,它都会调整单个项目的高度,并且看起来只有一个,但您实际上可以滚动列表。而是手动设置 RecyclerView 的高度。
【讨论】:
【参考方案5】:对于最近遇到此问题并且正在运行支持库的 SDK 28 测试版的用户,请将您的目标 SDK 更改为 27 并使用支持库的 27.1.1 版本(撰写本文时的最新版本)。
我在 28.0.0-alpha3 库上遇到了这个问题,在我的 app.gradle 中将版本更改为 27.1.1,问题就解决了。
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support:design:27.1.1'
implementation 'com.android.support:support-vector-drawable:27.1.1'
implementation 'com.android.support:recyclerview-v7:27.1.1'
【讨论】:
【参考方案6】:注意 RecyclerView 循环中的 onBindViewHolder 行为。 RecyclerView.ViewHolder位置0 itemView
android:layout_
占据当前显示的屏幕。 Scroll 和 onBindViewHolder 应该被触发,但要确保 getItemCount 设置正确。
解决方案:
android:layout_
ConstraintLayout 作为膨胀的 itemView 的解决方案:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_
android:layout_><!-- IMPORTANT -->
<!-- ... -->
</android.support.constraint.ConstraintLayout>
【讨论】:
【参考方案7】:问题不在您的代码中。确保将 RecyclerView 子项的 layout_height
设置为 wrap_content
。
【讨论】:
我同意代码可以正常工作。我检查了子项的layout_height
属性,发现它们都设置为wrap_content
。我很确定问题出在库上。
是的,wrap_content 不像 match_parent 那样占据整个屏幕。这种方式 onBind 被称为其他时间更多
子项是什么意思?
子项表示行布局
谢谢!我在这上面浪费了很多时间!【参考方案8】:
对所有支持库使用相同的版本:
dependencies
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.3.0'
compile 'com.android.support:design:23.3.0'
compile 'com.android.support:support-v4:23.3.0'
compile 'com.android.support:recyclerview-v7:23.3.0' //<<< here
此外,RecyclerView
应与 'com.android.support:design:23.3.0'
包一起添加 - 覆盖类或 Gradle
在构建过程中使用此“重复”包所做的任何魔术都可能导致您的问题。
【讨论】:
不,它不起作用。 onBindViewHolder 只被调用一次。实际上,代码的最后一行就像您建议的那样,但我认为我应该坚持使用我曾经使用的库,所以我在发布时进行了更改。清理和重建项目不会改变结果。以上是关于RecyclerView.onBindViewHolder 只调用一次的主要内容,如果未能解决你的问题,请参考以下文章