Как обновить данные адаптера RecyclerView?
пытаюсь выяснить в чем проблема с обновлением 'ы.
после того, как я получаю новый список продуктов, я попытался:
обновить
ArrayListиз фрагмента, гдеrecyclerViewсоздается, устанавливает новые данные в адаптер, затем вызываетadapter.notifyDataSetChanged(); это не сработало.создать новый адаптер, как это делали другие, и он работал для них, но никаких изменений для меня:
recyclerView.setAdapter(new RecyclerViewAdapter(newArrayList))
создать метод в
Adapterкоторый обновляет данные следующим образом:
public void updateData(ArrayList<ViewModel> viewModels) {
items.clear();
items.addAll(viewModels);
notifyDataSetChanged();
}
затем я вызываю этот метод всякий раз, когда я хочу обновить список данных, он не работал.
чтобы проверить, могу ли я каким-либо образом изменить recyclerView, и я попытался удалить хотя бы элемент:
public void removeItem(int position) {
items.remove(position);
notifyItemRemoved(position);
}
все осталось как и было.
вот мой адаптер:
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);
}
}
и я инициирую RecyclerView как следует:
recyclerView = (RecyclerView) view.findViewById(R.id.recycler);
recyclerView.setLayoutManager(new GridLayoutManager(getActivity(), 5));
adapter = new RecyclerViewAdapter(items);
adapter.setOnItemClickListener(this);
recyclerView.setAdapter(adapter);
Итак, как мне на самом деле обновить данные адаптера для отображения вновь полученных элементов?
обновление: проблема заключалась в том, что макет, где gridView выглядел следующим образом:
<?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>
тогда я просто удалил LinearLayout и составила FrameLayout как макет родителей.
12 ответов:
Я работаю с RecyclerView и оба удаления и обновления работают хорошо.
1) удалить: Есть 4 шага, чтобы удалить элемент из RecyclerView
list.remove(position); recycler.removeViewAt(position); mAdapter.notifyItemRemoved(position); mAdapter.notifyItemRangeChanged(position, list.size());эти строки кодов работают для меня.
2) ОБНОВЛЕНИЕ ДАННЫХ: Единственное, что я должен был сделать, это
mAdapter.notifyDataSetChanged();вы должны были сделать все это в коде Actvity/Fragment, а не в коде адаптера RecyclerView.
это общий ответ для будущих посетителей. Описаны различные способы обновления данных адаптера. Процесс включает в себя два основных шага каждый раз:
- обновить набор данных
- уведомить адаптер об изменении
вставить один элемент
добавить "свинья" по индексу
2.
String item = "Pig"; int insertIndex = 2; data.add(insertIndex, item); adapter.notifyItemInserted(insertIndex);вставить несколько элементов
вставить еще три животных в индекс
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());удалить один элемент
удалить "свинью" из списка.
int removeIndex = 2; data.remove(removeIndex); adapter.notifyItemRemoved(removeIndex);удалить несколько элементов
удалить "верблюд" и "овца" из списка.
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);удалить все элементы
очистить весь список.
data.clear(); adapter.notifyDataSetChanged();заменить старый список на новый список
снимите старый список, а затем добавить новый.
// 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();The
adapterимеет ссылку наdata, поэтому важно, чтобы я не устанавливалdataк новому объекту. Вместо этого я очистил старые элементы отdataа затем добавил новые.обновить один элемент
измените пункт " овцы "так, чтобы он говорил:" мне нравятся овцы."
String newValue = "I like sheep."; int updateIndex = 3; data.set(updateIndex, newValue); adapter.notifyItemChanged(updateIndex);переместить один элемент
переместить "овец" из положения
3в положение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);код
вот код проекта для вашей справки. Код адаптера RecyclerView можно найти по адресу ответ.
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); } }Примечания
- если вы используете
notifyDataSetChanged(), тогда анимация не будет выполнена. Это также может быть дорогим операции, поэтому не рекомендуется использоватьnotifyDataSetChanged()если вы обновляете только один элемент или диапазон элементов.- проверить DiffUtil если вы делаете большие или сложные изменения в список.
дальнейшего изучения
это то, что сработало для меня:
recyclerView.setAdapter(new RecyclerViewAdapter(newList)); recyclerView.invalidate();после создания нового адаптера, который содержит обновленный список (в моем случае это была база данных, преобразованная в ArrayList) и установки этого адаптера, я попытался
recyclerView.invalidate()и это сработало.
у вас есть 2 варианта для этого: обновить пользовательский интерфейс из адаптера:
mAdapter.notifyDataSetChanged();или обновить его из самого recyclerView:
recyclerView.invalidate();
другой вариант-использовать diffutil . Он будет сравнивать исходный список с новым списком и использовать новый список в качестве обновления, если есть изменения.
в принципе, мы можем использовать DiffUtil для сравнения старых данных с новыми данными и пусть он вызывает notifyItemRangeRemoved, и notifyItemRangeChanged и notifyItemRangeInserted от вашего имени.
быстрый пример использования diffUtil вместо 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)Я делаю calclateDiff работает с основным потоком, если это большой список.
обновление данных listview, gridview и recyclerview
mAdapter.notifyDataSetChanged();или
mAdapter.notifyItemRangeChanged(0, itemList.size());
Я решил ту же проблему по-другому. У меня нет данных, которые я жду от фонового потока, поэтому начните со списка 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(); }вот и все.
лучший и самый крутой способ добавить новые данные к настоящим данным-это
ArrayList<String> newItems = new ArrayList<String>(); newItems = getList(); int oldListItemscount = alcontainerDetails.size(); alcontainerDetails.addAll(newItems); recyclerview.getAdapter().notifyItemChanged(oldListItemscount+1, al_containerDetails);
я узнал, что действительно простой способ перезагрузить RecyclerView - это просто позвонить
recyclerView.removeAllViews();это сначала удалит все содержимое RecyclerView, а затем добавит его снова с обновленными значениями.
Я получил ответ после долгого времени
SELECTEDROW.add(dt); notifyItemInserted(position); SELECTEDROW.remove(position); notifyItemRemoved(position);
Если ничего не упоминается в приведенных выше комментариях работает для вас. Это может означать, что проблема лежит где-то еще.
одно место, где я нашел решение, было в том, как я устанавливал список на адаптер. В моей деятельности список был переменной экземпляра, и я менял его непосредственно при изменении любых данных. Из-за того, что это была ссылочная переменная, происходило что-то странное. Поэтому я изменил ссылочную переменную на локальную и использовал другую переменную для обновления данных, а затем перейти к
addAll()функция, упомянутая в приведенных выше ответах.
эти методы эффективны и хороши, чтобы начать использовать базовый
RecyclerView.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(); }вы можете реализовать их внутри класса адаптера или в своем фрагменте или действии, но в этом случае вам нужно создать экземпляр адаптера для вызова методов уведомления. В моем случае я обычно реализую его в адаптере.








Comments