【问题标题】:RecyclerView.onBindViewHolder called only onceRecyclerView.onBindViewHolder 只调用一次
【发布时间】: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 库一起使用怎么办?

标签: android dependencies android-recyclerview android-studio-2.0


【解决方案1】:

在我的情况下,recyclerview 的单项布局的根布局(约束布局)高度设置为 ma​​tch_parent 而不是 'wrap_content',将其更改为 'wrap_content' 和问题是固定的

<androidx.constraintlayout.widget.ConstraintLayout 
android:layout_width="match_parent"
android:layout_height="wrap_content">

<androidx.cardview.widget.CardView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    tools:ignore="MissingConstraints">

    <TextView
        android:id="@+id/tv_city_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        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()。当我向适配器添加不同的项目时,它们具有相同 idonBindViewHolder 在滚动时停止调用。所以,我从

    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 ids 的集合。

    【讨论】:

      【解决方案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_height="match_parent"
            

            占据当前显示的屏幕。 Scroll 和 onBindViewHolder 应该被触发,但要确保 getItemCount 设置正确。

            解决方案:

            android:layout_height="wrap_content"
            

            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_width="match_parent"
                android:layout_height="wrap_content"><!-- 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 只被调用一次。实际上,代码的最后一行就像您建议的那样,但我认为我应该坚持使用我曾经使用的库,所以我在发布时进行了更改。清理和重建项目不会改变结果。
              猜你喜欢
              • 1970-01-01
              • 2017-06-08
              • 2013-01-09
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多