Tentando descobrir qual é o problema com RecyclerView
o adaptador da atualização .
Depois de receber uma nova lista de produtos, tentei:
Atualize a
ArrayList
partir do fragmento em querecyclerView
é criado, configure novos dados para o adaptador e chameadapter.notifyDataSetChanged()
; não funcionou.Crie um novo adaptador, como outros fizeram, e funcionou para eles, mas nenhuma alteração para mim:
recyclerView.setAdapter(new RecyclerViewAdapter(newArrayList))
Crie um método no
Adapter
qual atualize os dados da seguinte maneira:public void updateData(ArrayList<ViewModel> viewModels) { items.clear(); items.addAll(viewModels); notifyDataSetChanged(); }
Então eu chamo esse método sempre que quiser atualizar a lista de dados; não funcionou.
Para verificar se eu posso modificar o recyclerView de alguma forma e tentei remover pelo menos um item:
public void removeItem(int position) { items.remove(position); notifyItemRemoved(position); }
Tudo permaneceu como estava.
Aqui está o meu 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 da RecyclerView
seguinte forma:
recyclerView = (RecyclerView) view.findViewById(R.id.recycler);
recyclerView.setLayoutManager(new GridLayoutManager(getActivity(), 5));
adapter = new RecyclerViewAdapter(items);
adapter.setOnItemClickListener(this);
recyclerView.setAdapter(adapter);
Então, como atualizo os dados do adaptador para exibir os itens recém-recebidos?
Atualização: o problema era que o layout em que gridView era o seguinte:
<?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>
Então eu apenas removi LinearLayout
e fiz FrameLayout
como layout pai.
fonte
items.clear(); items.addAll(newItems);
é um padrão feio. Se você realmente precisa de cópias defensivas aqui,items = new ArrayList(newItems);
seria menos feio.Respostas:
Estou trabalhando com o RecyclerView e a remoção e a atualização funcionam bem.
1) REMOVER: Existem 4 etapas para remover um item de um RecyclerView
Essas linhas de códigos funcionam para mim.
2) ATUALIZAR OS DADOS: As únicas coisas que eu tinha que fazer é
Você precisava fazer tudo isso no código do Actvity / Fragment e não no código do RecyclerView Adapter.
fonte
recycler.removeViewAt(position);
(ou melhorrecycler.removeAllViews()
) foram as cruciais.Esta é uma resposta geral para futuros visitantes. As várias maneiras de atualizar os dados do adaptador são explicadas. O processo inclui duas etapas principais todas as vezes:
Inserir item único
Adicione "Pig" no índice
2
.Inserir vários itens
Insira mais três animais no índice
2
.Remover item único
Remova "Pig" da lista.
Remova vários itens
Remova "Camel" e "Sheep" da lista.
Remova todos os itens
Limpe a lista inteira.
Substituir lista antiga por nova lista
Limpe a lista antiga e adicione uma nova.
O
adapter
tem uma referência adata
, por isso é importante que eu não tenha definidodata
um novo objeto. Em vez disso, limpei os itens antigosdata
e os adicionei.Atualizar item único
Mude o item "Ovelha" para que ele diga "Eu gosto de ovelha".
Mover item único
Mova "Ovelha" de uma posição
3
para outra1
.Código
Aqui está o código do projeto para sua referência. O código do adaptador RecyclerView pode ser encontrado nesta resposta .
MainActivity.java
Notas
notifyDataSetChanged()
, nenhuma animação será executada. Também pode ser uma operação cara, portanto, não é recomendável usarnotifyDataSetChanged()
se você estiver atualizando apenas um único item ou um intervalo de itens.Um estudo mais aprofundado
fonte
Update single item
, deveria ter sido como tartarugasIsto é o que funcionou para mim:
Depois de criar um novo adaptador que contém a lista atualizada (no meu caso, era um banco de dados convertido em um ArrayList) e defini-lo como adaptador, tentei
recyclerView.invalidate()
e funcionou.fonte
YourAdapter adapter = (YourAdapter) recyclerView.getAdapter(); adapter.yourSetterMethod(newList); adapter.notifyDataSetChanged();
Dito isto, soa como o que o OP tentou primeiro (apenas adicionando isso como um comentário para que ele possa ajudar outra pessoa, como funcionou no meu caso).você tem 2 opções para fazer isso: atualize a interface do usuário do adaptador:
ou atualize-o a partir do recyclerView:
fonte
Outra opção é usar o diffutil . Ele comparará a lista original com a nova lista e usará a nova lista como atualização, se houver uma alteração.
Basicamente, podemos usar o DiffUtil para comparar os dados antigos e os novos e deixá-lo chamar notifyItemRangeRemoved, e notifyItemRangeChanged e notifyItemRangeInserted em seu nome.
Um exemplo rápido do uso de diffUtil em vez de notifyDataSetChanged:
Eu faço o trabalho calculado com o thread principal, caso seja uma grande lista.
fonte
getItems()
. Como você sabe quais dados da lista original precisam ser removidos / adicionados / atualizados?Atualizar dados de listview, gridview e recyclerview
ou
fonte
A melhor e a maneira mais legal de adicionar novos dados aos dados atuais é
fonte
Eu resolvi o mesmo problema de uma maneira diferente. Eu não tenho dados esperando por eles do thread em segundo plano, então comece com uma lista emty.
É isso aí.
fonte
Esses métodos são eficientes e bons para começar a usar um básico
RecyclerView
.Você pode implementá-los dentro de uma classe de adaptador ou em seu fragmento ou atividade, mas nesse caso você precisa instanciar o adaptador para chamar os métodos de notificação. No meu caso, eu normalmente o implico no adaptador.
fonte
Eu descobri que uma maneira muito simples de recarregar o RecyclerView é apenas chamar
Isso removerá primeiro todo o conteúdo do RecyclerView e o adicionará novamente com os valores atualizados.
fonte
eu recebi a resposta depois de muito tempo
fonte
Se nada mencionado nos comentários acima estiver funcionando para você. Isso pode significar que o problema está em outro lugar.
Um local em que encontrei a solução foi a maneira como defini a lista para o adaptador. Na minha atividade, a lista era uma variável de instância e eu a alterava diretamente quando qualquer dado era alterado. Por ser uma variável de referência, havia algo estranho acontecendo. Então, mudei a variável de referência para local e usei outra variável para atualizar os dados e depois passar para a
addAll()
função mencionada nas respostas acima.fonte