【问题标题】:Need an example about RecyclerView.Adapter.notifyItemChanged(int position, Object payload)需要一个关于 RecyclerView.Adapter.notifyItemChanged(int position, Object payload) 的例子
【发布时间】:2019-04-12 17:42:32
【问题描述】:

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

通过可选的有效负载对象通知任何已注册的观察者该位置的项目已更改。

我不明白如何在这个方法中使用第二个参数payload。我搜索了许多关于“有效载荷”的文档,但一切都模棱两可。

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

【问题讨论】:

    标签: android android-recyclerview payload


    【解决方案1】:

    如果您想更新不是全部持有人视图,而只是更新其中的一部分,那么这种方法就是您所需要的。

    您关注的图像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.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
            }
    

    【讨论】:

    • 为什么它是一个有效载荷列表呢?在哪种情况下,列表中有多个对象?如果您在同一位置多次调用 notifyItemChanged ?
    • 如果你使用 Kotlin,提示载荷类型是 Any,而在 Java 中是 Object,所以你可以传递任何你想要的东西。稍后您将在onBindViewHolder(ViewHolder holder, int position, List&lt;Object&gt; payloads) 中投射您的对象。查看更多信息:developer.android.com/reference/android/support/v7/widget/…, java.lang.Object)
    • 经过数小时努力寻找解决方案后,这个解决方案奏效了。非常感谢:)
    • @androiddeveloper 你可能已经弄明白了,但对于未来的读者:是的,如果你用多个有效载荷通知同一个位置,它们将作为这些对象的列表传递给onBindViewHolder()跨度>
    【解决方案2】:

    查看演示该功能的示例代码。这是一个RecyclerView,当单击位置position 的项目时调用notifyItemChanged(position, payload)。您可以通过查找 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>
    

    【讨论】:

    • 我刚刚测试了你的代码。我的测试中有一些无用的东西:基本的 onBind(没有有效负载)永远不会被调用。你现在为什么?我只是调用 notifyItemRangeChanged(index, mArrayList.size());或 notifyItemInserted(i);
    • 爱不成熟的日志标签+1
    【解决方案3】:

    基本上,将有效负载视为常量要方便得多。
    如果数据集中已发生更改,则无需在此处传递任何数据。
    因此,创建几个常量:

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

    【讨论】:

    • 是的,在某种意义上它是一个标签
    • 是的,它使用有效载荷按预期工作。谢谢列昂尼德·乌斯滕科
    【解决方案4】:

    当您只想在调用onBindViewHolder 方法时对ViewHolder 中的数据执行部分更新时,您可以传入一个“可选负载对象”。但是,不确定是否会始终传递有效负载,例如,如果未附加视图,则应执行更多检查。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-07-08
      • 2015-04-18
      • 2022-06-14
      • 2012-07-20
      • 1970-01-01
      • 1970-01-01
      • 2014-10-19
      相关资源
      最近更新 更多