Вступ
Оскільки з вашого питання не зовсім зрозуміло, з чим саме у вас виникають проблеми, я написав цей короткий посібник про те, як реалізувати цю функцію; якщо у вас все ще є запитання, не соромтеся задавати питання.
У мене є робочий приклад того, про що я говорю тут, у цьому сховищі GitHub .
Якщо ви хочете дізнатися більше про приклад проекту, відвідайте домашню сторінку проекту .
У будь-якому випадку результат повинен виглядати приблизно так:
Якщо ви спершу хочете пограти з демонстраційним додатком, ви можете встановити його з Play Store:
Все одно давайте почнемо.
Налаштування SearchView
У папці res/menu
створіть новий файл під назвою main_menu.xml
. У неї додати елемент і встановити actionViewClass
в android.support.v7.widget.SearchView
. Оскільки ви використовуєте бібліотеку підтримки, вам потрібно використовувати простір імен бібліотеки підтримки, щоб встановити actionViewClass
атрибут. Ваш XML-файл повинен виглядати приблизно так:
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/action_search"
android:title="@string/action_search"
app:actionViewClass="android.support.v7.widget.SearchView"
app:showAsAction="always"/>
</menu>
У своєму Fragment
або Activity
вам доведеться надути це меню xml як звичайне, тоді ви можете шукати, MenuItem
що містить SearchView
і реалізувати те, OnQueryTextListener
що ми збираємось використати для прослуховування змін у тексті, введеному в SearchView
:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
final MenuItem searchItem = menu.findItem(R.id.action_search);
final SearchView searchView = (SearchView) searchItem.getActionView();
searchView.setOnQueryTextListener(this);
return true;
}
@Override
public boolean onQueryTextChange(String query) {
// Here is where we are going to implement the filter logic
return false;
}
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
І тепер SearchView
готовий до використання. Ми будемо реалізовувати логіку фільтра згодом, onQueryTextChange()
як тільки ми закінчимо реалізацію Adapter
.
Налаштування Adapter
Перш за все це клас моделей, який я збираюся використовувати для цього прикладу:
public class ExampleModel {
private final long mId;
private final String mText;
public ExampleModel(long id, String text) {
mId = id;
mText = text;
}
public long getId() {
return mId;
}
public String getText() {
return mText;
}
}
Це просто ваша основна модель, яка відобразить текст у полі RecyclerView
. Це макет, який я буду використовувати для відображення тексту:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="model"
type="com.github.wrdlbrnft.searchablerecyclerviewdemo.ui.models.ExampleModel"/>
</data>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:clickable="true">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp"
android:text="@{model.text}"/>
</FrameLayout>
</layout>
Як ви бачите, я використовую прив'язку даних. Якщо ви ніколи не працювали з прив'язкою даних раніше, не перешкоджайте! Це дуже просто і потужно, проте я не можу пояснити, як це працює в рамках цієї відповіді.
Це ViewHolder
для ExampleModel
класу:
public class ExampleViewHolder extends RecyclerView.ViewHolder {
private final ItemExampleBinding mBinding;
public ExampleViewHolder(ItemExampleBinding binding) {
super(binding.getRoot());
mBinding = binding;
}
public void bind(ExampleModel item) {
mBinding.setModel(item);
}
}
Знову нічого особливого. Він просто використовує прив'язку даних для прив'язки класу моделі до цього макета, як ми визначили в макеті xml вище.
Тепер ми можемо нарешті підійти до дійсно цікавої частини: Написання адаптера. Я збираюся пропустити основну реалізацію Adapter
і замість цього зосереджуся на частинах, які мають значення для цієї відповіді.
Але спочатку є одне, про що ми повинні поговорити: SortedList
Клас.
SortedList
Це SortedList
абсолютно дивовижний інструмент, який є частиною RecyclerView
бібліотеки. Він піклується про сповіщення Adapter
про зміни в наборі даних і робить це дуже ефективним способом. Єдине, що вам потрібно зробити - це вказати порядок елементів. Вам потрібно зробити це, застосувавши compare()
метод, який порівнює два елементи SortedList
просто так, як Comparator
. Але замість сортування a List
використовується для сортування елементів у RecyclerView
!
У SortedList
взаємодіє з Adapter
через Callback
клас , який ви повинні реалізувати:
private final SortedList.Callback<ExampleModel> mCallback = new SortedList.Callback<ExampleModel>() {
@Override
public void onInserted(int position, int count) {
mAdapter.notifyItemRangeInserted(position, count);
}
@Override
public void onRemoved(int position, int count) {
mAdapter.notifyItemRangeRemoved(position, count);
}
@Override
public void onMoved(int fromPosition, int toPosition) {
mAdapter.notifyItemMoved(fromPosition, toPosition);
}
@Override
public void onChanged(int position, int count) {
mAdapter.notifyItemRangeChanged(position, count);
}
@Override
public int compare(ExampleModel a, ExampleModel b) {
return mComparator.compare(a, b);
}
@Override
public boolean areContentsTheSame(ExampleModel oldItem, ExampleModel newItem) {
return oldItem.equals(newItem);
}
@Override
public boolean areItemsTheSame(ExampleModel item1, ExampleModel item2) {
return item1.getId() == item2.getId();
}
}
У способах у верхній частині зворотного виклику , як onMoved
, onInserted
і т.д. Ви повинні викликати еквівалент повідомить вами спосіб Adapter
. Три способи внизу compare
, areContentsTheSame
і areItemsTheSame
ви повинні реалізувати відповідно до того, який тип об’єктів ви хочете відображати та в якому порядку ці об'єкти повинні з’являтися на екрані.
Давайте переглянемо ці методи по черзі:
@Override
public int compare(ExampleModel a, ExampleModel b) {
return mComparator.compare(a, b);
}
Це compare()
метод, про який я говорив раніше. У цьому прикладі я просто передаю дзвінок на те, Comparator
що порівнює дві моделі. Якщо ви хочете, щоб елементи відображалися в алфавітному порядку на екрані. Цей порівняльник може виглядати приблизно так:
private static final Comparator<ExampleModel> ALPHABETICAL_COMPARATOR = new Comparator<ExampleModel>() {
@Override
public int compare(ExampleModel a, ExampleModel b) {
return a.getText().compareTo(b.getText());
}
};
Тепер розглянемо наступний метод:
@Override
public boolean areContentsTheSame(ExampleModel oldItem, ExampleModel newItem) {
return oldItem.equals(newItem);
}
Мета цього методу - визначити, чи змінився вміст моделі. В SortedList
використовує це , щоб визначити , чи потребує викликатися подія зміни - іншими словами , якщо RecyclerView
необхідно кроссфейд стару і нову версію. Якщо у модельних класах є правильна equals()
та hashCode()
реалізація, зазвичай ви можете просто реалізувати її, як вище. Якщо ми додамо equals()
та додаток hashCode()
до ExampleModel
класу, він повинен виглядати приблизно так:
public class ExampleModel implements SortedListAdapter.ViewModel {
private final long mId;
private final String mText;
public ExampleModel(long id, String text) {
mId = id;
mText = text;
}
public long getId() {
return mId;
}
public String getText() {
return mText;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ExampleModel model = (ExampleModel) o;
if (mId != model.mId) return false;
return mText != null ? mText.equals(model.mText) : model.mText == null;
}
@Override
public int hashCode() {
int result = (int) (mId ^ (mId >>> 32));
result = 31 * result + (mText != null ? mText.hashCode() : 0);
return result;
}
}
Швидка зауваження: у більшості IDE, таких як Android Studio, IntelliJ та Eclipse, є функціонал для створення equals()
та hashCode()
реалізації для вас одним натисненням кнопки! Тож вам не доведеться їх реалізовувати самостійно. Подивіться в Інтернеті, як це працює у вашому IDE!
Тепер давайте розглянемо останній метод:
@Override
public boolean areItemsTheSame(ExampleModel item1, ExampleModel item2) {
return item1.getId() == item2.getId();
}
Цей SortedList
метод використовує для перевірки, чи два елементи відносяться до однієї речі. Найпростіше кажучи (не пояснюючи, як це SortedList
працює), це використовується для визначення того, чи об’єкт уже міститься в програмі, List
і чи потрібно відтворювати анімацію додавання, переміщення або зміни. Якщо у ваших моделей є ідентифікатор, ви зазвичай порівнюєте лише ідентифікатор у цьому методі. Якщо вони не потребують іншого способу, щоб перевірити це, але ви все-таки реалізуєте це, залежить від конкретного додатка. Зазвичай це найпростіший варіант, щоб надати всім моделям ідентифікатор - який, наприклад, може бути полем первинного ключа, якщо ви запитуєте дані з бази даних.
При SortedList.Callback
правильному виконанні ми можемо створити екземпляр SortedList
:
final SortedList<ExampleModel> list = new SortedList<>(ExampleModel.class, mCallback);
В якості першого параметра в конструкторі SortedList
вам потрібно передати клас ваших моделей. Інший параметр - це лише SortedList.Callback
визначений нами вище.
Тепер приступимо до справи: Якщо ми реалізуємо Adapter
з a, SortedList
це має виглядати приблизно так:
public class ExampleAdapter extends RecyclerView.Adapter<ExampleViewHolder> {
private final SortedList<ExampleModel> mSortedList = new SortedList<>(ExampleModel.class, new SortedList.Callback<ExampleModel>() {
@Override
public int compare(ExampleModel a, ExampleModel b) {
return mComparator.compare(a, b);
}
@Override
public void onInserted(int position, int count) {
notifyItemRangeInserted(position, count);
}
@Override
public void onRemoved(int position, int count) {
notifyItemRangeRemoved(position, count);
}
@Override
public void onMoved(int fromPosition, int toPosition) {
notifyItemMoved(fromPosition, toPosition);
}
@Override
public void onChanged(int position, int count) {
notifyItemRangeChanged(position, count);
}
@Override
public boolean areContentsTheSame(ExampleModel oldItem, ExampleModel newItem) {
return oldItem.equals(newItem);
}
@Override
public boolean areItemsTheSame(ExampleModel item1, ExampleModel item2) {
return item1.getId() == item2.getId();
}
});
private final LayoutInflater mInflater;
private final Comparator<ExampleModel> mComparator;
public ExampleAdapter(Context context, Comparator<ExampleModel> comparator) {
mInflater = LayoutInflater.from(context);
mComparator = comparator;
}
@Override
public ExampleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
final ItemExampleBinding binding = ItemExampleBinding.inflate(inflater, parent, false);
return new ExampleViewHolder(binding);
}
@Override
public void onBindViewHolder(ExampleViewHolder holder, int position) {
final ExampleModel model = mSortedList.get(position);
holder.bind(model);
}
@Override
public int getItemCount() {
return mSortedList.size();
}
}
Comparator
Використовується для сортування пункт передається через конструктор , тому ми можемо використовувати один і той же , Adapter
навіть якщо елементи повинні відображатися в іншому порядку.
Зараз ми майже готові! Але для початку нам потрібен спосіб додавання або видалення елементів до Adapter
. З цією метою ми можемо додати методи, до Adapter
яких можна додавати та видаляти елементи до SortedList
:
public void add(ExampleModel model) {
mSortedList.add(model);
}
public void remove(ExampleModel model) {
mSortedList.remove(model);
}
public void add(List<ExampleModel> models) {
mSortedList.addAll(models);
}
public void remove(List<ExampleModel> models) {
mSortedList.beginBatchedUpdates();
for (ExampleModel model : models) {
mSortedList.remove(model);
}
mSortedList.endBatchedUpdates();
}
Нам тут не потрібно викликати будь-які способи сповіщення, оскільки це SortedList
вже робиться через SortedList.Callback
! Крім цього, реалізація цих методів є досить прямою вперед за одним винятком: метод видалення, який видаляє List
модель. Оскільки SortedList
існує лише один метод видалення, який може видалити один об'єкт, нам потрібно перевести список і видалити моделі по черзі. Виклик beginBatchedUpdates()
на початку містить усі зміни, які ми збираємось внести SortedList
разом, і покращує продуктивність. Коли ми називаємо повідомляється про всі зміни відразу.endBatchedUpdates()
RecyclerView
Крім того, ви повинні розуміти, що якщо ви додасте об'єкт до SortedList
і він вже є, SortedList
він більше не буде доданий. Натомість SortedList
використовує areContentsTheSame()
метод, щоб з'ясувати, чи змінився об'єкт - і чи є у нього елемент у RecyclerView
заповіті буде оновлено.
У будь-якому випадку, як правило, я вважаю за краще один метод, який дозволяє мені замінити всі елементи в RecyclerView
одразу. Видаліть усе, чого немає, List
і додайте всі елементи, які відсутні у SortedList
:
public void replaceAll(List<ExampleModel> models) {
mSortedList.beginBatchedUpdates();
for (int i = mSortedList.size() - 1; i >= 0; i--) {
final ExampleModel model = mSortedList.get(i);
if (!models.contains(model)) {
mSortedList.remove(model);
}
}
mSortedList.addAll(models);
mSortedList.endBatchedUpdates();
}
Цей метод знову збирає всі оновлення разом для підвищення продуктивності. Перший цикл знаходиться в зворотному порядку, оскільки вилучення елемента на початку може зіпсувати індекси всіх елементів, які з’являються після нього, і це може призвести в деяких випадках до проблем, таких як невідповідності даних. Після цього ми просто додаємо List
до SortedList
використовуваного, addAll()
щоб додати всі елементи, які вже не перебувають у - SortedList
і, як я описав вище, - оновити всі елементи, які вже є, SortedList
але змінилися.
І цим Adapter
є повне. Вся справа повинна виглядати приблизно так:
public class ExampleAdapter extends RecyclerView.Adapter<ExampleViewHolder> {
private final SortedList<ExampleModel> mSortedList = new SortedList<>(ExampleModel.class, new SortedList.Callback<ExampleModel>() {
@Override
public int compare(ExampleModel a, ExampleModel b) {
return mComparator.compare(a, b);
}
@Override
public void onInserted(int position, int count) {
notifyItemRangeInserted(position, count);
}
@Override
public void onRemoved(int position, int count) {
notifyItemRangeRemoved(position, count);
}
@Override
public void onMoved(int fromPosition, int toPosition) {
notifyItemMoved(fromPosition, toPosition);
}
@Override
public void onChanged(int position, int count) {
notifyItemRangeChanged(position, count);
}
@Override
public boolean areContentsTheSame(ExampleModel oldItem, ExampleModel newItem) {
return oldItem.equals(newItem);
}
@Override
public boolean areItemsTheSame(ExampleModel item1, ExampleModel item2) {
return item1 == item2;
}
});
private final Comparator<ExampleModel> mComparator;
private final LayoutInflater mInflater;
public ExampleAdapter(Context context, Comparator<ExampleModel> comparator) {
mInflater = LayoutInflater.from(context);
mComparator = comparator;
}
@Override
public ExampleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
final ItemExampleBinding binding = ItemExampleBinding.inflate(mInflater, parent, false);
return new ExampleViewHolder(binding);
}
@Override
public void onBindViewHolder(ExampleViewHolder holder, int position) {
final ExampleModel model = mSortedList.get(position);
holder.bind(model);
}
public void add(ExampleModel model) {
mSortedList.add(model);
}
public void remove(ExampleModel model) {
mSortedList.remove(model);
}
public void add(List<ExampleModel> models) {
mSortedList.addAll(models);
}
public void remove(List<ExampleModel> models) {
mSortedList.beginBatchedUpdates();
for (ExampleModel model : models) {
mSortedList.remove(model);
}
mSortedList.endBatchedUpdates();
}
public void replaceAll(List<ExampleModel> models) {
mSortedList.beginBatchedUpdates();
for (int i = mSortedList.size() - 1; i >= 0; i--) {
final ExampleModel model = mSortedList.get(i);
if (!models.contains(model)) {
mSortedList.remove(model);
}
}
mSortedList.addAll(models);
mSortedList.endBatchedUpdates();
}
@Override
public int getItemCount() {
return mSortedList.size();
}
}
Єдине, чого зараз бракує, це здійснити фільтрацію!
Реалізація логіки фільтра
Для реалізації логіки фільтру спершу треба визначити a List
з усіх можливих моделей. Для цього прикладу я створюю List
з ExampleModel
примірників з масиву фільмів:
private static final String[] MOVIES = new String[]{
...
};
private static final Comparator<ExampleModel> ALPHABETICAL_COMPARATOR = new Comparator<ExampleModel>() {
@Override
public int compare(ExampleModel a, ExampleModel b) {
return a.getText().compareTo(b.getText());
}
};
private ExampleAdapter mAdapter;
private List<ExampleModel> mModels;
private RecyclerView mRecyclerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
mAdapter = new ExampleAdapter(this, ALPHABETICAL_COMPARATOR);
mBinding.recyclerView.setLayoutManager(new LinearLayoutManager(this));
mBinding.recyclerView.setAdapter(mAdapter);
mModels = new ArrayList<>();
for (String movie : MOVIES) {
mModels.add(new ExampleModel(movie));
}
mAdapter.add(mModels);
}
Нічого особливого не відбувається тут, ми просто створимо його Adapter
і встановимо його RecyclerView
. Після цього ми створюємо List
моделі з імен фільмів у MOVIES
масиві. Потім ми додаємо всі моделі до SortedList
.
Тепер ми можемо повернутися до того, onQueryTextChange()
що ми визначили раніше, і розпочати реалізацію логіки фільтра:
@Override
public boolean onQueryTextChange(String query) {
final List<ExampleModel> filteredModelList = filter(mModels, query);
mAdapter.replaceAll(filteredModelList);
mBinding.recyclerView.scrollToPosition(0);
return true;
}
Це знову досить прямо вперед. Ми називаємо метод filter()
і передати в List
з ExampleModel
х, а також в рядку запиту. Потім ми викликаємо replaceAll()
на Adapter
і передати в відфільтрованої List
повертається filter()
. Ми також повинні викликати scrollToPosition(0)
на RecyclerView
для того, щоб користувач завжди може побачити всі деталі при пошуку чогось - то. Інакше RecyclerView
під час фільтрування ви можете залишитися в положенні прокрутки вниз і згодом приховати кілька елементів. Прокручування до верху забезпечує кращу роботу користувачів під час пошуку.
Єдине, що залишилося зараз зробити - це реалізувати filter()
себе:
private static List<ExampleModel> filter(List<ExampleModel> models, String query) {
final String lowerCaseQuery = query.toLowerCase();
final List<ExampleModel> filteredModelList = new ArrayList<>();
for (ExampleModel model : models) {
final String text = model.getText().toLowerCase();
if (text.contains(lowerCaseQuery)) {
filteredModelList.add(model);
}
}
return filteredModelList;
}
Перше, що ми робимо тут - це дзвінок toLowerCase()
у рядку запиту. Ми не хочемо, щоб наша пошукова функція була чутливою до регістру, і, зателефонувавши toLowerCase()
до всіх порівняних рядків, ми можемо забезпечити повернення однакових результатів незалежно від випадку. Потім він просто повторює всі моделі в List
ми передали в нього і перевіряє, чи рядок запиту міститься в тексті моделі. Якщо це так, модель додається до відфільтрованого List
.
І це все! Наведений вище код працюватиме на рівні 7 і вище API, і, починаючи з рівня 11 API, ви отримуєте анімацію предмета безкоштовно!
Я розумію, що це дуже детальний опис, який, ймовірно, робить всю цю справу більш складною, ніж є насправді, але є спосіб, як ми можемо узагальнити всю цю проблему та зробити реалізацію на Adapter
основі SortedList
набагато простішою.
Узагальнення проблеми та спрощення адаптера
У цьому розділі я не збираюся детально описуватись - частково тому, що я переживаю обмеження символів для відповідей на переповнення стека, а також тому, що більшість із них уже пояснено вище - але підсумовую зміни: Ми можемо реалізувати базовий Adapter
клас яка вже піклується про поводження з SortedList
моделями, а також прив'язування до ViewHolder
примірників і забезпечує зручний спосіб реалізації Adapter
основи на основі SortedList
. Для цього ми повинні зробити дві речі:
- Нам потрібно створити
ViewModel
інтерфейс, який мають реалізувати всі класи моделей
- Нам потрібно створити
ViewHolder
підклас, який визначає bind()
метод, який Adapter
можна використовувати для автоматичного прив’язування моделей.
Це дозволяє нам просто зосередитись на вмісті, який повинен бути відображений у RecyclerView
простому впровадженні моделей, а також відповідних ViewHolder
реалізаціях. Використовуючи цей базовий клас, нам не потрібно турбуватися про складні деталі Adapter
та його SortedList
.
SortedListAdapter
Через обмеження символів для відповідей на StackOverflow я не можу пройти кожен етап реалізації цього базового класу або навіть додати тут повний вихідний код, але ви можете знайти повний вихідний код цього базового класу - я його назвав SortedListAdapter
- у цьому GitHub Gist .
Щоб зробити ваше життя простим, я опублікував бібліотеку на jCenter, яка містить SortedListAdapter
! Якщо ви хочете використовувати його, то все, що вам потрібно зробити, це додати цю залежність до файлу build.gradle програми:
compile 'com.github.wrdlbrnft:sorted-list-adapter:0.2.0.1'
Ви можете знайти більше інформації про цю бібліотеку на домашній сторінці бібліотеки .
Використання SortedListAdapter
Для використання SortedListAdapter
ми повинні внести дві зміни:
Змініть ViewHolder
так, щоб він розширився SortedListAdapter.ViewHolder
. Параметр типу повинен бути моделлю, яка повинна бути пов'язана з цим ViewHolder
- в цьому випадку ExampleModel
. Ви повинні прив’язувати дані до своїх моделей performBind()
замість bind()
.
public class ExampleViewHolder extends SortedListAdapter.ViewHolder<ExampleModel> {
private final ItemExampleBinding mBinding;
public ExampleViewHolder(ItemExampleBinding binding) {
super(binding.getRoot());
mBinding = binding;
}
@Override
protected void performBind(ExampleModel item) {
mBinding.setModel(item);
}
}
Переконайтесь, що всі ваші моделі реалізують ViewModel
інтерфейс:
public class ExampleModel implements SortedListAdapter.ViewModel {
...
}
Після цього нам просто потрібно оновити ExampleAdapter
розширення SortedListAdapter
та видалити все, що більше не потрібно. Параметр типу повинен бути типом моделі, з якою ви працюєте - в цьому випадку ExampleModel
. Але якщо ви працюєте з моделями різних типів, тоді встановіть параметр типу ViewModel
.
public class ExampleAdapter extends SortedListAdapter<ExampleModel> {
public ExampleAdapter(Context context, Comparator<ExampleModel> comparator) {
super(context, ExampleModel.class, comparator);
}
@Override
protected ViewHolder<? extends ExampleModel> onCreateViewHolder(LayoutInflater inflater, ViewGroup parent, int viewType) {
final ItemExampleBinding binding = ItemExampleBinding.inflate(inflater, parent, false);
return new ExampleViewHolder(binding);
}
@Override
protected boolean areItemsTheSame(ExampleModel item1, ExampleModel item2) {
return item1.getId() == item2.getId();
}
@Override
protected boolean areItemContentsTheSame(ExampleModel oldItem, ExampleModel newItem) {
return oldItem.equals(newItem);
}
}
Після цього ми робимо! Однак одне останнє, що слід зазначити: У них SortedListAdapter
немає тих же методів add()
, remove()
чи у replaceAll()
наших оригіналів ExampleAdapter
. Він використовує окремий Editor
об'єкт для зміни елементів у списку, до яких можна отримати доступ edit()
методом. Отже, якщо ви хочете видалити або додати елементи, вам потрібно зателефонувати, edit()
потім додайте та видаліть елементи цього Editor
примірника, і як тільки ви це зробите, зателефонуйте commit()
йому, щоб застосувати зміни до SortedList
:
mAdapter.edit()
.remove(modelToRemove)
.add(listOfModelsToAdd)
.commit();
Усі внесені вами зміни збираються разом для підвищення продуктивності. replaceAll()
Метод ми реалізували в попередніх розділах також присутній на цьому Editor
об'єкті:
mAdapter.edit()
.replaceAll(mModels)
.commit();
Якщо ви забудете зателефонувати, commit()
то жодна з ваших змін не буде застосована!