需要一个关于 RecyclerView.Adapter.notifyItemChanged(int position, Object payload) 的例子

Need an example about RecyclerView.Adapter.notifyItemChanged(int position, Object payload)

根据 RecyclerView 有关方法的文档 notifyItemChanged(int position, Object payload)

Notify any registered observers that the item at position has changed with an optional payload object.

我不明白如何在此方法中使用第二个参数 payload。我搜索了很多关于 "payload" 的文档,但一切都模棱两可。

所以,如果你知道这个方法,请给我一个清楚的例子。非常感谢。

调用onBindViewHolder方法时,如果只想对ViewHolder中的数据进行部分更新,可以传入"optional payload object"。但是,并不确定负载是否始终会被传递,例如,如果未附加视图,那么您应该执行更多检查。

无论如何,如果您通过 null,它将对该项目执行完整更新,您不必担心。

查看演示此功能的示例代码。单击位置 position 处的项目时,它是调用 notifyItemChanged(position, payload)RecyclerView。您可以通过查找 logcat 语句来验证是否调用了 onBindViewHolder(holder, position, payload)

确保您至少使用 23.1.1 版本的支持库,如下所示:

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>

如果你想更新不是所有 holder View,而是部分,这个方法就是你需要的。

您关注的图片 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);
        }

    }

并且在代码的某处调用适配器来更新 single TextView - tvScore

mRecyclerViewAdapter.notifyItemChanged(position, new Integer(4533));

[...]

onBindViewHolder(ViewHolder holder, int position, List payloads) 首先捕获回调。 如果 payloads 不符合您的要求,您必须强制调用 super class super.onBindViewHolder(holder,position, payloads);,这会在其他情况下触发 onBindViewHolder(ViewHolder holder, int position)

     // 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
        }

基本上,将有效负载视为常量会更方便。
如果数据集中已更改,则您不必将任何数据传递到那里。
因此,创建几个常量:

public static final String PAYLOAD_NAME = "PAYLOAD_NAME";
public static final String PAYLOAD_AGE = "PAYLOAD_AGE";

然后在适配器中,除了更新整个项目的常规 onBindViewHolder(YourViweHolder holder, int position) 之外,例如:

@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()));
}

您还实现了:

@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);
    }
}

您可以根据需要处理任意数量的案例,并且仅更新实际更改的视图。
最后一步 - 您只需执行:

adapter.notifyItemChanged(somePosition, YourAdapter.PAYLOAD_NAME);