web-dev-qa-db-fra.com

Besoin d'un exemple sur RecyclerView.Adapter.notifyItemChanged (int position, Object payload)

Selon RecyclerView documentation sur medthod notifyItemChanged (int position, charge utile)

Avertissez tous les observateurs inscrits que l'élément à la position a été modifié avec un objet de charge utile facultatif.

Je ne comprends pas comment utiliser le second paramètre payload dans cette méthode. J'ai cherché de nombreux documents sur "charge utile" mais tout était ambigu.

Donc, si vous connaissez cette méthode, montrez-moi un exemple clair à ce sujet. Merci beaucoup.

Consultez cet exemple de code qui illustre la fonctionnalité. C'est un RecyclerView qui appelle notifyItemChanged(position, payload) lorsque l'élément à la position position est cliqué. Vous pouvez vérifier que onBindViewHolder(holder, position, payload) a été appelé en recherchant l'instruction logcat.

Assurez-vous que vous utilisez au moins la version 23.1.1 des bibliothèques de support, comme ceci:

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>
30
Patricia Li

Si vous souhaitez mettre à jour pas tous le détenteur mais juste ne partie, cette méthode est ce dont vous avez besoin.

Image que vous avez suivante 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);
        }

    }

Et quelque part dans votre code, vous appelez un adaptateur pour mettre à jour single TextView - tvScore

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

[...]

( onBindViewHolder (titulaire de ViewHolder, position int, liste des charges utiles)) intercepte le rappel au premier abord. Si payloads ne correspond pas à vos besoins, vous devez obligatoirement appeler la super-classe super.onBindViewHolder(holder,position, payloads); qui déclenchera onBindViewHolder(ViewHolder holder, int position) pour les autres cas.

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

En gros, il est beaucoup plus pratique de traiter les charges utiles comme des constantes.
Vous n’avez pas besoin de transmettre de données si celles-ci ont déjà été modifiées dans le jeu de données.
Créez donc deux constantes:

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

Ensuite, dans l'adaptateur, en plus d'une onBindViewHolder(YourViweHolder holder, int position) normale où vous mettez à jour tout l'élément, par exemple:

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

vous implémentez également:

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

Vous pouvez gérer autant de cas que nécessaire et mettre à jour uniquement les vues réellement modifiées.
La dernière étape - vous venez de faire:

adapter.notifyItemChanged(somePosition, YourAdapter.PAYLOAD_NAME);
3
Leo Droidcoder

Vous pouvez passer un "objet de charge optionnel" lorsque vous souhaitez simplement effectuer une mise à jour partielle des données dans le ViewHolder lorsque la méthode onBindViewHolder est appelée. Toutefois, il n’est pas certain que les données utiles seront toujours transmises, par exemple si la vue n’est pas attachée. Vous devez donc effectuer quelques vérifications supplémentaires.

Quoi qu'il en soit, si vous passez null, une mise à jour complète de l'élément sera effectuée et vous n'aurez pas à vous en préoccuper.

1
marcerv