update studio recyclerview data como change actualizar android android-recyclerview

android - studio - ¿Cómo actualizar los datos del adaptador RecyclerView?



refresh adapter android (12)

Intentando averiguar cuál es el problema con la actualización del adaptador RecyclerView .

Después de obtener una nueva Lista de productos, intenté:

  1. Actualice ArrayList desde el fragmento donde se crea recyclerView , establezca nuevos datos en el adaptador, luego llame a adapter.notifyDataSetChanged() ; No funcionó.

  2. Cree un nuevo adaptador, como lo hicieron otros, y funcionó para ellos, pero no hay cambio para mí: recyclerView.setAdapter(new RecyclerViewAdapter(newArrayList))

  3. Cree un método en Adapter que actualice los datos de la siguiente manera:

    public void updateData(ArrayList<ViewModel> viewModels) { items.clear(); items.addAll(viewModels); notifyDataSetChanged(); }

    Luego llamo a este método cada vez que quiero actualizar la lista de datos; No funcionó.

  4. Para comprobar si puedo modificar el recyclerView de alguna manera, e intenté eliminar al menos un elemento:

    public void removeItem(int position) { items.remove(position); notifyItemRemoved(position); }

    Todo quedó como estaba.

Aquí está mi adaptador:

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> implements View.OnClickListener { private ArrayList<ViewModel> items; private OnItemClickListener onItemClickListener; public RecyclerViewAdapter(ArrayList<ViewModel> items) { this.items = items; } public void setOnItemClickListener(OnItemClickListener onItemClickListener) { this.onItemClickListener = onItemClickListener; } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_recycler, parent, false); v.setOnClickListener(this); return new ViewHolder(v); } public void updateData(ArrayList<ViewModel> viewModels) { items.clear(); items.addAll(viewModels); notifyDataSetChanged(); } public void addItem(int position, ViewModel viewModel) { items.add(position, viewModel); notifyItemInserted(position); } public void removeItem(int position) { items.remove(position); notifyItemRemoved(position); } @Override public void onBindViewHolder(ViewHolder holder, int position) { ViewModel item = items.get(position); holder.title.setText(item.getTitle()); Picasso.with(holder.image.getContext()).load(item.getImage()).into(holder.image); holder.price.setText(item.getPrice()); holder.credit.setText(item.getCredit()); holder.description.setText(item.getDescription()); holder.itemView.setTag(item); } @Override public int getItemCount() { return items.size(); } @Override public void onClick(final View v) { // Give some time to the ripple to finish the effect if (onItemClickListener != null) { new Handler().postDelayed(new Runnable() { @Override public void run() { onItemClickListener.onItemClick(v, (ViewModel) v.getTag()); } }, 0); } } protected static class ViewHolder extends RecyclerView.ViewHolder { public ImageView image; public TextView price, credit, title, description; public ViewHolder(View itemView) { super(itemView); image = (ImageView) itemView.findViewById(R.id.image); price = (TextView) itemView.findViewById(R.id.price); credit = (TextView) itemView.findViewById(R.id.credit); title = (TextView) itemView.findViewById(R.id.title); description = (TextView) itemView.findViewById(R.id.description); } } public interface OnItemClickListener { void onItemClick(View view, ViewModel viewModel); } }

E inicio RecyclerView siguiente manera:

recyclerView = (RecyclerView) view.findViewById(R.id.recycler); recyclerView.setLayoutManager(new GridLayoutManager(getActivity(), 5)); adapter = new RecyclerViewAdapter(items); adapter.setOnItemClickListener(this); recyclerView.setAdapter(adapter);

Entonces, ¿cómo actualizo los datos del adaptador para mostrar los elementos recién recibidos?

Actualización: el problema era que el diseño donde gridView se veía de la siguiente manera:

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:tag="catalog_fragment" android:layout_height="match_parent"> <FrameLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.RecyclerView android:id="@+id/recycler" android:layout_width="match_parent" android:layout_height="match_parent" android:clipToPadding="false"/> <ImageButton android:id="@+id/fab" android:layout_gravity="top|end" style="@style/FabStyle"/> </FrameLayout> </LinearLayout>

Luego simplemente LinearLayout e hice FrameLayout como diseño principal.


Actualizar datos de vista de lista, vista de cuadrícula y vista de reciclado

mAdapter.notifyDataSetChanged();

o

mAdapter.notifyItemRangeChanged(0, itemList.size());


Descubrí que una forma realmente simple de recargar el RecyclerView es simplemente llamar

recyclerView.removeAllViews();

Esto eliminará primero todo el contenido de RecyclerView y luego lo agregará nuevamente con los valores actualizados.


Esta es una respuesta general para futuros visitantes. Se explican las diversas formas de actualizar los datos del adaptador. El proceso incluye dos pasos principales cada vez:

  1. Actualizar el conjunto de datos
  2. Notificar al adaptador del cambio

Insertar elemento individual

Agregue "Pig" en el índice 2 .

String item = "Pig"; int insertIndex = 2; data.add(insertIndex, item); adapter.notifyItemInserted(insertIndex);

Insertar elementos múltiples

Inserte tres animales más en el índice 2 .

ArrayList<String> items = new ArrayList<>(); items.add("Pig"); items.add("Chicken"); items.add("Dog"); int insertIndex = 2; data.addAll(insertIndex, items); adapter.notifyItemRangeInserted(insertIndex, items.size());

Eliminar un solo artículo

Eliminar "Pig" de la lista.

int removeIndex = 2; data.remove(removeIndex); adapter.notifyItemRemoved(removeIndex);

Eliminar varios elementos

Elimina "Camel" y "Sheep" de la lista.

int startIndex = 2; // inclusive int endIndex = 4; // exclusive int count = endIndex - startIndex; // 2 items will be removed data.subList(startIndex, endIndex).clear(); adapter.notifyItemRangeRemoved(startIndex, count);

Eliminar todos los artículos

Borra toda la lista.

data.clear(); adapter.notifyDataSetChanged();

Reemplazar lista antigua con lista nueva

Borre la lista anterior y luego agregue una nueva.

// clear old list data.clear(); // add new list ArrayList<String> newList = new ArrayList<>(); newList.add("Lion"); newList.add("Wolf"); newList.add("Bear"); data.addAll(newList); // notify adapter adapter.notifyDataSetChanged();

El adapter tiene una referencia a los data , por lo que es importante que no haya configurado los data en un nuevo objeto. En cambio, borré los elementos antiguos de los data y luego agregué los nuevos.

Actualizar elemento individual

Cambie el elemento "Ovejas" para que diga "Me gustan las ovejas".

String newValue = "I like sheep."; int updateIndex = 3; data.set(updateIndex, newValue); adapter.notifyItemChanged(updateIndex);

Mover un solo elemento

Mueva "Sheep" de la posición 3 a la posición 1 .

int fromPosition = 3; int toPosition = 1; // update data array String item = data.get(fromPosition); data.remove(fromPosition); data.add(toPosition, item); // notify adapter adapter.notifyItemMoved(fromPosition, toPosition);

Código

Aquí está el código del proyecto para su referencia. El código del adaptador RecyclerView se puede encontrar en esta respuesta .

MainActivity.java

public class MainActivity extends AppCompatActivity implements MyRecyclerViewAdapter.ItemClickListener { List<String> data; MyRecyclerViewAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // data to populate the RecyclerView with data = new ArrayList<>(); data.add("Horse"); data.add("Cow"); data.add("Camel"); data.add("Sheep"); data.add("Goat"); // set up the RecyclerView RecyclerView recyclerView = findViewById(R.id.rvAnimals); LinearLayoutManager layoutManager = new LinearLayoutManager(this); recyclerView.setLayoutManager(layoutManager); DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(), layoutManager.getOrientation()); recyclerView.addItemDecoration(dividerItemDecoration); adapter = new MyRecyclerViewAdapter(this, data); adapter.setClickListener(this); recyclerView.setAdapter(adapter); } @Override public void onItemClick(View view, int position) { Toast.makeText(this, "You clicked " + adapter.getItem(position) + " on row number " + position, Toast.LENGTH_SHORT).show(); } public void onButtonClick(View view) { insertSingleItem(); } private void insertSingleItem() { String item = "Pig"; int insertIndex = 2; data.add(insertIndex, item); adapter.notifyItemInserted(insertIndex); } private void insertMultipleItems() { ArrayList<String> items = new ArrayList<>(); items.add("Pig"); items.add("Chicken"); items.add("Dog"); int insertIndex = 2; data.addAll(insertIndex, items); adapter.notifyItemRangeInserted(insertIndex, items.size()); } private void removeSingleItem() { int removeIndex = 2; data.remove(removeIndex); adapter.notifyItemRemoved(removeIndex); } private void removeMultipleItems() { int startIndex = 2; // inclusive int endIndex = 4; // exclusive int count = endIndex - startIndex; // 2 items will be removed data.subList(startIndex, endIndex).clear(); adapter.notifyItemRangeRemoved(startIndex, count); } private void removeAllItems() { data.clear(); adapter.notifyDataSetChanged(); } private void replaceOldListWithNewList() { // clear old list data.clear(); // add new list ArrayList<String> newList = new ArrayList<>(); newList.add("Lion"); newList.add("Wolf"); newList.add("Bear"); data.addAll(newList); // notify adapter adapter.notifyDataSetChanged(); } private void updateSingleItem() { String newValue = "I like sheep."; int updateIndex = 3; data.set(updateIndex, newValue); adapter.notifyItemChanged(updateIndex); } private void moveSingleItem() { int fromPosition = 3; int toPosition = 1; // update data array String item = data.get(fromPosition); data.remove(fromPosition); data.add(toPosition, item); // notify adapter adapter.notifyItemMoved(fromPosition, toPosition); } }

Notas

  • Si usa notifyDataSetChanged() , no se realizará ninguna animación. Esto también puede ser una operación costosa, por lo que no se recomienda utilizar notifyDataSetChanged() si solo está actualizando un solo elemento o un rango de elementos.
  • Consulte DiffUtil si está realizando cambios grandes o complejos en una lista.

Estudio adicional


Esto es lo que funcionó para mí:

recyclerView.setAdapter(new RecyclerViewAdapter(newList)); recyclerView.invalidate();

Después de crear un nuevo adaptador que contiene la lista actualizada (en mi caso, era una base de datos convertida en una ArrayList) y configurarlo como adaptador, probé recyclerView.invalidate() y funcionó.


Estos métodos son eficientes y buenos para comenzar a usar un RecyclerView básico.

private List<YourItem> items; public void setItems(List<YourItem> newItems) { clearItems(); addItems(newItems); } public void addItem(YourItem item, int position) { if (position > items.size()) return; items.add(item); notifyItemInserted(position); } public void addMoreItems(List<YourItem> newItems) { int position = items.size() + 1; newItems.addAll(newItems); notifyItemChanged(position, newItems); } public void addItems(List<YourItem> newItems) { items.addAll(newItems); notifyDataSetChanged(); } public void clearItems() { items.clear(); notifyDataSetChanged(); } public void addLoader() { items.add(null); notifyItemInserted(items.size() - 1); } public void removeLoader() { items.remove(items.size() - 1); notifyItemRemoved(items.size()); } public void removeItem(int position) { if (position >= items.size()) return; items.remove(position); notifyItemRemoved(position); } public void swapItems(int positionA, int positionB) { if (positionA > items.size()) return; if (positionB > items.size()) return; YourItem firstItem = items.get(positionA); videoList.set(positionA, items.get(positionB)); videoList.set(positionB, firstItem); notifyDataSetChanged(); }

Puede implementarlos dentro de una Clase de adaptador o en su Fragmento o Actividad, pero en ese caso debe crear una instancia del Adaptador para llamar a los métodos de notificación. En mi caso, generalmente lo implemento en el adaptador.


Estoy trabajando con RecyclerView y tanto la eliminación como la actualización funcionan bien.

1) ELIMINAR: hay 4 pasos para eliminar un elemento de un RecyclerView

list.remove(position); recycler.removeViewAt(position); mAdapter.notifyItemRemoved(position); mAdapter.notifyItemRangeChanged(position, list.size());

Esta línea de códigos me funciona.

2) ACTUALIZAR LOS DATOS: lo único que tuve que hacer es

mAdapter.notifyDataSetChanged();

Tuviste que hacer todo esto en el código Actvity / Fragment no en el código del adaptador RecyclerView.


He resuelto el mismo problema de una manera diferente. No tengo datos, los espero del hilo de fondo, así que comience con una lista de emty.

mAdapter = new ModelAdapter(getContext(),new ArrayList<Model>()); // then when i get data mAdapter.update(response.getModelList()); // and update is in my adapter public void update(ArrayList<Model> modelList){ adapterModelList.clear(); for (Product model: modelList) { adapterModelList.add(model); } mAdapter.notifyDataSetChanged(); }

Eso es.


La mejor y la mejor manera de agregar nuevos datos a los datos actuales es

ArrayList<String> newItems = new ArrayList<String>(); newItems = getList(); int oldListItemscount = alcontainerDetails.size(); alcontainerDetails.addAll(newItems); recyclerview.getAdapter().notifyItemChanged(oldListItemscount+1, al_containerDetails);


Otra opción es usar DiffUtil . Comparará la lista original con la nueva lista y usará la nueva lista como la actualización si hay un cambio.

Básicamente, podemos usar DiffUtil para comparar los datos antiguos con los nuevos y dejar que llame a notifyItemRangeRemoved, y notifyItemRangeChanged y notifyItemRangeInserted en su nombre.

Un ejemplo rápido del uso de diffUtil en lugar de notifyDataSetChanged:

DiffResult diffResult = DiffUtil .calculateDiff(new MyDiffUtilCB(getItems(), items)); //any clear up on memory here and then diffResult.dispatchUpdatesTo(this); //and then, if necessary items.clear() items.addAll(newItems)

Hago el trabajo CalculateDiff fuera del hilo principal en caso de que sea una lista grande.


Si nada de lo mencionado en los comentarios anteriores funciona para usted. Podría significar que el problema se encuentra en otro lugar.

Un lugar donde encontré la solución fue en la forma en que estaba configurando la lista para el adaptador. En mi actividad, la lista era una variable de instancia y la estaba cambiando directamente cuando cambiaba cualquier dato. Debido a que es una variable de referencia, sucedía algo extraño. Así que cambié la variable de referencia a una local y usé otra variable para actualizar los datos y luego pasar a la función addAll() mencionada en las respuestas anteriores.


recibí la respuesta después de mucho tiempo

SELECTEDROW.add(dt); notifyItemInserted(position); SELECTEDROW.remove(position); notifyItemRemoved(position);


tiene 2 opciones para hacer esto: actualizar la interfaz de usuario desde el adaptador:

mAdapter.notifyDataSetChanged();

o actualizarlo desde el reciclador Ver sí mismo:

recyclerView.invalidate();