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é:
-
Actualice
ArrayList
desde el fragmento donde se crearecyclerView
, establezca nuevos datos en el adaptador, luego llame aadapter.notifyDataSetChanged()
; No funcionó. -
Cree un nuevo adaptador, como lo hicieron otros, y funcionó para ellos, pero no hay cambio para mí:
recyclerView.setAdapter(new RecyclerViewAdapter(newArrayList))
-
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ó.
-
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:
- Actualizar el conjunto de datos
- 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 utilizarnotifyDataSetChanged()
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();