Need an example about RecyclerView.Adapter.notifyItemChanged(int position, Object payload)
If you want to update not all holder View but just part of it, this method is what you need.
Image that you have following ViewHolder
public class ViewHolder extends RecyclerView.ViewHolder {
public final TextView tvPlayer;
public final TextView tvScore;
public ViewHolder(View view) {
super(view);
tvPlayer = (TextView) view.findViewById(R.id.tv_player);
tvScore = (TextView) view.findViewById(R.id.tv_score);
}
}
And somewhere in your code you call adapter to update single TextView - tvScore
mRecyclerViewAdapter.notifyItemChanged(position, new Integer(4533));
[...]
onBindViewHolder(ViewHolder holder, int position, List payloads) catches callback at first.
If payloads
doesn't match your requirements you have to obligatory call super class super.onBindViewHolder(holder,position, payloads);
which trigger onBindViewHolder(ViewHolder holder, int position)
for other cases.
// Update only part of ViewHolder that you are interested in
// Invoked before onBindViewHolder(ViewHolder holder, int position)
@Override
public void onBindViewHolder(ViewHolder holder, int position, List<Object> payloads) {
if(!payloads.isEmpty()) {
if (payloads.get(0) instanceof Integer) {
holder.tvScore.setText(String.valueOf((Integer)payloads.get(0)))
}
}else {
super.onBindViewHolder(holder,position, payloads);
}
}
// Update ALL VIEW holder
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
MItem item = mList.get(position)
// some update
}
Check out this sample code that demonstrates the feature. It's a RecyclerView
that calls notifyItemChanged(position, payload)
when the item at position position
is clicked. You can verify that onBindViewHolder(holder, position, payload)
was called by looking for the logcat statement.
Make sure you are using at least version 23.1.1
of the support libraries, like so:
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:23.1.1'
compile 'com.android.support:recyclerview-v7:23.1.1'
compile 'com.android.support:cardview-v7:23.1.1'
}
HelloActivity.java
package com.formagrid.hellotest;
import android.app.Activity;
import android.os.Bundle;
import android.support.v7.widget.CardView;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.List;
public class HelloActivity extends Activity {
private RecyclerView mRecyclerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
mRecyclerView.setAdapter(new HelloAdapter());
DefaultItemAnimator animator = new DefaultItemAnimator() {
@Override
public boolean canReuseUpdatedViewHolder(RecyclerView.ViewHolder viewHolder) {
return true;
}
};
mRecyclerView.setItemAnimator(animator);
}
private static class HelloAdapter extends RecyclerView.Adapter<HelloAdapter.HelloViewHolder> {
public class HelloViewHolder extends RecyclerView.ViewHolder {
public TextView textView;
public HelloViewHolder(CardView cardView) {
super(cardView);
textView = (TextView) cardView.findViewById(R.id.text_view);
}
}
@Override
public HelloViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
CardView cardView = (CardView) LayoutInflater.from(parent.getContext()).inflate(
R.layout.card_item, parent, false);
return new HelloViewHolder(cardView);
}
@Override
public void onBindViewHolder(HelloViewHolder holder, int position) {
bind(holder);
}
@Override
public void onBindViewHolder(HelloViewHolder holder, int position, List<Object> payload) {
Log.d("butt", "payload " + payload.toString());
bind(holder);
}
@Override
public int getItemCount() {
return 20;
}
private void bind(final HelloViewHolder holder) {
holder.textView.setText("item " + holder.getAdapterPosition());
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final int position = holder.getAdapterPosition();
Log.d("butt", "click " + position);
HelloAdapter.this.notifyItemChanged(position, "payload " + position);
}
});
}
}
}
activity_main.xml
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".HelloActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
card_item.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="100dip"
android:layout_margin="5dip"
card_view:cardElevation="5dip">
<TextView
android:id="@+id/text_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</android.support.v7.widget.CardView>
Basically, it's much more convenient to treat payloads as constants.
You don't have to pass any data there if it's already changed in the dataset.
So, create a couple of constants:
public static final String PAYLOAD_NAME = "PAYLOAD_NAME";
public static final String PAYLOAD_AGE = "PAYLOAD_AGE";
Then in the adapter, besides a regular onBindViewHolder(YourViweHolder holder, int position)
where you update the whole item, for instance:
@Override
public void onBindViewHolder(final YourViewHolder holder, final int position) {
final YourItem item = getItem(position);
holder.tvName.setText(item.getName());
holder.tvAge.setText(String.valueOf(item.getAge()));
}
you also implement:
@Override
public void onBindViewHolder(final YourViewHolder holder, final int position, final List<Object> payloads) {
if (!payloads.isEmpty()) {
final YourItem item = getItem(position);
for (final Object payload : payloads) {
if (payload.equals(PAYLOAD_NAME)) {
// in this case only name will be updated
holder.tvName.setText(item.getName());
} else if (payload.equals(PAYLOAD_AGE)) {
// only age will be updated
holder.tvAge.setText(String.valueOf(item.getAge()));
}
}
} else {
// in this case regular onBindViewHolder will be called
super.onBindViewHolder(holder, position, payloads);
}
}
You can handle as many cases as you need and update only views that actually changed.
The last step - you just do:
adapter.notifyItemChanged(somePosition, YourAdapter.PAYLOAD_NAME);