Vitalii
Vitalii

Reputation: 11071

Binding in RecyclerView binds data to multiple rows

I become crazy with databinding in RecyclerView. The problem is that it binds data to multiple rows and I can't figure out why.

I simplified my code as much as possible. When we start the application there is a 200 rows with a label (empty value by default) and a button. When I click a button my label changes it's value.

So here is a opened activity. As you can see no label is displayed.

enter image description here

Let's click a button at the first row

enter image description here

As expected label appearned at correct position. Let's scroll now.

enter image description here

We can see that label appeared also at 11th position, 21st, etc. Any ideas why?

My Adapter:

 @NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
    ListLearnItemBinding itemBinding = ListLearnItemBinding.inflate(layoutInflater, parent, false);
    return new LearnItemViewHolder(itemBinding);
}

@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
    final LearnItemViewHolder viewHolder = (LearnItemViewHolder) holder;
    // init binding
    if(viewHolder.getBinding().getItem2() == null){
        TestBinding t = new TestBinding();
        t.setRating("");
        viewHolder.getBinding().setItem2(t);
    }

    viewHolder.getBinding().test.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            TestBinding item2 = new TestBinding();
            item2.setRating("Label");
            viewHolder.bind(item2);
        }
    });
}

@Override
public int getItemCount() {
    return 200;
}

ViewHolder:

public class LearnItemViewHolder extends RecyclerView.ViewHolder {
    public ListLearnItemBinding getBinding() {
        return binding;
    }

    private final ListLearnItemBinding binding;

    public LearnItemViewHolder(ListLearnItemBinding binding) {
        super(binding.getRoot());
        this.binding = binding;
    }

    public void bind(TestBinding testItem) {
        binding.setItem2(testItem);
        binding.executePendingBindings();
    }
}

Binding model

public class TestBinding {
    public String getRating() {
        return rating;
    }

    public void setRating(String rating) {
        this.rating = rating;
    }

    private String rating;
}

OnCreate of my view

    binding.recyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
    binding.recyclerView.setItemAnimator(new DefaultItemAnimator());
    LearnAdapter mAdapter = new LearnAdapter(this, data);     
    binding.recyclerView.setAdapter(mAdapter);

Layout

  <TextView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="@{String.valueOf(item2.rating)}" />

  <Button
      android:id="@+id/test"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_alignParentTop="true"
      android:layout_marginTop="20dp"
      />

Upvotes: 0

Views: 320

Answers (1)

Samuel Eminet
Samuel Eminet

Reputation: 4737

This happens because when you're scrolling old views are being resused for optimization. You need something like this :

private List<String> mList;

@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
    final LearnItemViewHolder viewHolder = (LearnItemViewHolder) holder;

    TestBinding t = new TestBinding();
    t.setRating(mList.get( position);
    viewHolder.bind(t);

    viewHolder.getBinding().test.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            TestBinding item2 = new TestBinding();
            String label ="Label";
            item2.setRating(label);
            mList.set(position, label);
            viewHolder.bind(item2);
        }
    });
}

@Override
public int getItemCount() {
    return mList.size();
}

Upvotes: 1

Related Questions