Wprowadzenie
Ponieważ z twojego pytania nie jest tak naprawdę jasne, z czym dokładnie masz problemy, napisałem ten krótki przewodnik na temat implementacji tej funkcji; jeśli nadal masz pytania, możesz je zadać.
Mam działający przykład wszystkiego, o czym mówię tutaj w tym repozytorium GitHub .
Jeśli chcesz dowiedzieć się więcej o przykładowym projekcie, odwiedź stronę główną projektu .
W każdym razie wynik powinien wyglądać mniej więcej tak:

Jeśli najpierw chcesz się pobawić aplikacją demonstracyjną, możesz zainstalować ją ze Sklepu Play:

W każdym razie zacznijmy.
Konfigurowanie SearchView
W folderze res/menuutwórz nowy plik o nazwie main_menu.xml. W niej dodać element i ustawić actionViewClasssię android.support.v7.widget.SearchView. Ponieważ korzystasz z biblioteki wsparcia, musisz użyć przestrzeni nazw biblioteki wsparcia, aby ustawić actionViewClassatrybut. Twój plik xml powinien wyglądać mniej więcej tak:
<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>
W swoim Fragmentlub Activitymusisz napompować to menu xml jak zwykle, możesz poszukać, MenuItemktóry zawiera SearchViewi zaimplementować, OnQueryTextListenerktórego będziemy używać, aby nasłuchiwać zmian w tekście wprowadzonym do 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;
}
A teraz SearchViewjest gotowy do użycia. Zaimplementujemy logikę filtrowania później, onQueryTextChange()gdy skończymy wdrażanie Adapter.
Konfigurowanie Adapter
Przede wszystkim jest to klasa modelu, której zamierzam użyć w tym przykładzie:
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;
}
}
To tylko podstawowy model, który wyświetla tekst w RecyclerView. Oto układ, którego zamierzam użyć do wyświetlenia tekstu:
<?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>
Jak widać, używam powiązania danych. Jeśli nigdy wcześniej nie pracowałeś z powiązaniem danych, nie zniechęcaj się! Jest to bardzo proste i wydajne, ale nie mogę wyjaśnić, jak to działa w zakresie tej odpowiedzi.
To jest ViewHolderdla ExampleModelklasy:
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);
}
}
Znowu nic specjalnego. Po prostu używa powiązania danych, aby powiązać klasę modelu z tym układem, jak zdefiniowaliśmy w powyższym pliku xml układu.
Teraz możemy wreszcie przejść do naprawdę interesującej części: pisania adaptera. Pominę podstawową implementację Adapteri zamiast tego skoncentruję się na częściach, które są istotne dla tej odpowiedzi.
Ale najpierw jest jedna rzecz, o której musimy porozmawiać: SortedListklasa.
SortedList
SortedListJest zupełnie niesamowite narzędzie, które jest częścią RecyclerViewbiblioteki. Dba o powiadamianie Adaptero zmianach w zestawie danych i robi to w bardzo wydajny sposób. Jedyne, co musisz zrobić, to określić kolejność elementów. Musisz to zrobić, implementując compare()metodę, która porównuje dwa elementy w SortedListtaki sam sposób jak Comparator. Ale zamiast sortowania Listsłuży do sortowania elementów w RecyclerView!
W SortedListwspółdziała z Adapterza pośrednictwem Callbackklasy, które trzeba realizować:
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();
}
}
W sposobach na górze jak zwrotnego onMoved, onInserteditp trzeba nazwać odpowiednikiem zawiadomić sposób dokonania Adapter. Trzy sposoby na dole compare, areContentsTheSamei areItemsTheSametrzeba zaimplementować według jakiego rodzaju obiektów, które mają być wyświetlane iw jakiej kolejności obiekty te powinny pojawić się na ekranie.
Przeanalizujmy kolejno te metody:
@Override
public int compare(ExampleModel a, ExampleModel b) {
return mComparator.compare(a, b);
}
To jest compare()metoda, o której mówiłem wcześniej. W tym przykładzie właśnie przekazuję połączenie do modelu, Comparatorktóry porównuje oba modele. Jeśli chcesz, aby elementy były wyświetlane na ekranie w kolejności alfabetycznej. Ten komparator może wyglądać następująco:
private static final Comparator<ExampleModel> ALPHABETICAL_COMPARATOR = new Comparator<ExampleModel>() {
@Override
public int compare(ExampleModel a, ExampleModel b) {
return a.getText().compareTo(b.getText());
}
};
Teraz spójrzmy na następną metodę:
@Override
public boolean areContentsTheSame(ExampleModel oldItem, ExampleModel newItem) {
return oldItem.equals(newItem);
}
Celem tej metody jest ustalenie, czy zawartość modelu uległa zmianie. Do SortedListużywa tego, aby ustalić, czy zdarzenie zmiana musi być wywoływany - innymi słowy, czy RecyclerViewnależy płynne przejście starą i nową wersję. Jeśli modelujesz klasy, masz poprawną equals()i hashCode()implementację, zazwyczaj możesz ją po prostu zaimplementować jak wyżej. Jeśli dodamy do klasy implementację equals()i , powinna ona wyglądać mniej więcej tak: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;
}
}
Krótka uwaga: większość IDE, takich jak Android Studio, IntelliJ i Eclipse, ma funkcję generowania equals()i hashCode()implementacji dla Ciebie za naciśnięciem jednego przycisku! Więc nie musisz ich wdrażać samodzielnie. Sprawdź w Internecie, jak to działa w twoim IDE!
Teraz spójrzmy na ostatnią metodę:
@Override
public boolean areItemsTheSame(ExampleModel item1, ExampleModel item2) {
return item1.getId() == item2.getId();
}
SortedListKorzysta z tej metody, aby sprawdzić, czy dwie pozycje odnoszą się do tego samego. Mówiąc najprościej (bez wyjaśnienia, jak SortedListdziała), służy to do ustalenia, czy obiekt jest już zawarty Listi czy należy odtworzyć animację dodania, przesunięcia lub zmiany. Jeśli twoje modele mają identyfikator, zwykle porównujesz tylko identyfikator w tej metodzie. Jeśli nie, musisz wymyślić inny sposób, aby to sprawdzić, ale w końcu wdrożenie tego zależy od konkretnej aplikacji. Zwykle jest to najprostsza opcja nadania wszystkim modelom identyfikatora - może to być na przykład pole klucza podstawowego, jeśli przeszukujesz dane z bazy danych.
Dzięki SortedList.Callbackpoprawnie zaimplementowanemu możemy utworzyć instancję SortedList:
final SortedList<ExampleModel> list = new SortedList<>(ExampleModel.class, mCallback);
Jako pierwszy parametr w konstruktorze SortedListmusisz przekazać klasę swoich modeli. Drugi parametr to po prostu SortedList.Callbackzdefiniowany powyżej.
Przejdźmy teraz do rzeczy : jeśli zaimplementujemy Adapterz SortedList, powinno to wyglądać mniej więcej tak:
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();
}
}
ComparatorUżywane do sortowania pozycja jest przekazywana przez konstruktora, dzięki czemu możemy korzystać z tego samego Adapter, nawet jeśli elementy mają być wyświetlane w innej kolejności.
Teraz już prawie gotowe! Ale najpierw potrzebujemy sposobu dodawania lub usuwania elementów do Adapter. W tym celu możemy dodać metody, Adapterktóre pozwalają nam dodawać i usuwać elementy do 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();
}
Nie musimy tutaj wywoływać żadnych metod powiadamiania, ponieważ SortedListjuż to robi za pośrednictwem SortedList.Callback! Poza tym implementacja tych metod jest dość prosta, z jednym wyjątkiem: metodą remove, która usuwa Listmodele. Ponieważ SortedListma tylko jedną metodę remove, która może usunąć pojedynczy obiekt, musimy zapętlić listę i usuwać modele jeden po drugim. Wezwanie beginBatchedUpdates()na początku grupuje wszystkie zmiany, które SortedListrazem wprowadzimy, i poprawia wydajność. Kiedy wzywamy jest powiadamiany o wszelkich zmianach na raz.endBatchedUpdates()RecyclerView
Ponadto musisz zrozumieć, że jeśli dodasz obiekt do obiektu, który SortedListjuż znajduje się w SortedListnim, nie zostanie dodany ponownie. Zamiast tego SortedListużywa tej areContentsTheSame()metody, aby dowiedzieć się, czy obiekt się zmienił - a jeśli ma element w, RecyclerViewzostanie zaktualizowany.
W każdym razie to, co zwykle wolę, to jedna metoda, która pozwala mi na zastąpienie wszystkich przedmiotów RecyclerViewnaraz. Usuń wszystko, czego nie ma w, Listi dodaj wszystkie elementy, których brakuje w 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();
}
Ta metoda ponownie grupuje wszystkie aktualizacje razem, aby zwiększyć wydajność. Pierwsza pętla jest odwrotna, ponieważ usunięcie elementu na początku zepsułoby indeksy wszystkich elementów, które pojawią się po nim, co może w niektórych przypadkach prowadzić do problemów, takich jak niespójności danych. Następnie dodajemy po prostu Listdo za SortedListpomocą, addAll()aby dodać wszystkie elementy, które nie są jeszcze w SortedList- i - jak opisano powyżej - zaktualizować wszystkie elementy, które już są w, SortedListale zostały zmienione.
I z tym Adapterjest kompletny. Całość powinna wyglądać mniej więcej tak:
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();
}
}
Jedyne, czego teraz brakuje, to wdrożenie filtrowania!
Implementacja logiki filtrowania
Aby zaimplementować logikę filtrowania, musimy najpierw zdefiniować Listwszystkie możliwe modele. W tym przykładzie utworzyć Listz ExampleModelprzypadków z tablicy filmy:
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);
}
Nic specjalnego się tutaj nie dzieje, po prostu tworzymy instancję Adapteri ustawiamy ją na RecyclerView. Następnie tworzymy Listmodele z nazw filmów w MOVIEStablicy. Następnie dodajemy wszystkie modele do SortedList.
Teraz możemy wrócić do onQueryTextChange()zdefiniowanej wcześniej i rozpocząć implementację logiki filtru:
@Override
public boolean onQueryTextChange(String query) {
final List<ExampleModel> filteredModelList = filter(mModels, query);
mAdapter.replaceAll(filteredModelList);
mBinding.recyclerView.scrollToPosition(0);
return true;
}
To znowu jest całkiem proste. Wywołujemy metodę filter()i przekazać w Listod ExampleModels, a także ciąg kwerendy. Następnie zadzwoń replaceAll()na Adapteri przekazać w filtrowane Listzwrócony przez filter(). Musimy również wezwać scrollToPosition(0)do, RecyclerViewaby upewnić się, że użytkownik zawsze widzi wszystkie elementy podczas wyszukiwania czegoś. W przeciwnym razie RecyclerViewfiltr może pozostać w przewijanej pozycji podczas filtrowania, a następnie ukryć kilka elementów. Przewijanie do góry zapewnia lepszą obsługę podczas wyszukiwania.
Jedyne, co pozostało do zrobienia, to wdrożenie filter()się:
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;
}
Pierwszą rzeczą, którą tutaj robimy, jest wywołanie toLowerCase()ciągu zapytania. Nie chcemy, aby nasza funkcja wyszukiwania rozróżniała toLowerCase()wielkość liter i wywołując wszystkie porównywane ciągi znaków możemy zagwarantować, że zwracamy te same wyniki bez względu na wielkość liter. Następnie iteruje tylko wszystkie modele, Listktóre do niego przeszliśmy i sprawdza, czy ciąg zapytania jest zawarty w tekście modelu. Jeśli tak, to model jest dodawany do filtrowanego List.
I to wszystko! Powyższy kod będzie działał na poziomie API 7 i wyższym, a począwszy od API poziomu 11 otrzymasz animacje przedmiotów za darmo!
Zdaję sobie sprawę, że jest to bardzo szczegółowy opis, który prawdopodobnie sprawia, że cała ta sprawa wydaje się bardziej skomplikowana niż w rzeczywistości, ale istnieje sposób na uogólnienie tego całego problemu i uczynienie implementacji Adapteropartym na SortedListznacznie prostszym.
Uogólnienie problemu i uproszczenie adaptera
W tej sekcji nie będę szczegółowo omawiał - częściowo dlatego, że wyczerpuję się limit znaków dla odpowiedzi na Przepełnienie stosu, ale także dlatego, że większość z nich już wyjaśniono powyżej - ale podsumowując zmiany: Możemy zaimplementować Adapterklasę podstawową który już zajmuje się radzeniem sobie z SortedListmodelami ViewHolderi ich wiązaniem z instancjami i zapewnia wygodny sposób implementacji modelu Adapteropartego na SortedList. W tym celu musimy zrobić dwie rzeczy:
- Musimy stworzyć
ViewModelinterfejs, który wszystkie klasy modeli muszą wdrożyć
- Musimy utworzyć
ViewHolderpodklasę, która definiuje bind()metodę, której Adaptermożna użyć do automatycznego wiązania modeli.
To pozwala nam skupić się na treści, która ma być wyświetlana po RecyclerViewprostu poprzez wdrożenie modeli i odpowiadających im ViewHolderimplementacji. Korzystając z tej klasy bazowej, nie musimy się martwić o skomplikowane szczegóły Adapteri SortedList.
SortedListAdapter
Z powodu limitu znaków w odpowiedziach na StackOverflow nie mogę przejść przez każdy etap implementacji tej klasy bazowej ani nawet dodać tutaj pełnego kodu źródłowego, ale pełny kod źródłowy tej klasy bazowej - nazwałem to SortedListAdapter- w tym GitHub Gist .
Aby ułatwić Ci życie, opublikowałem bibliotekę w jCenter, która zawiera SortedListAdapter! Jeśli chcesz go użyć, wystarczy dodać tę zależność do pliku build.gradle aplikacji:
compile 'com.github.wrdlbrnft:sorted-list-adapter:0.2.0.1'
Więcej informacji o tej bibliotece można znaleźć na stronie głównej biblioteki .
Korzystanie z SortedListAdapter
Aby użyć, SortedListAdaptermusimy wprowadzić dwie zmiany:
Zmień ViewHoldertak, aby się wydłużył SortedListAdapter.ViewHolder. Parametrem typu powinien być model, który powinien być z tym związany ViewHolder- w tym przypadku ExampleModel. Trzeba powiązać dane do modeli performBind()zamiast 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);
}
}
Upewnij się, że wszystkie modele implementują ViewModelinterfejs:
public class ExampleModel implements SortedListAdapter.ViewModel {
...
}
Następnie musimy tylko zaktualizować, ExampleAdapteraby rozszerzyć SortedListAdapteri usunąć wszystko, czego już nie potrzebujemy. Parametr typu powinien być typem modelu, z którym pracujesz - w tym przypadku ExampleModel. Ale jeśli pracujesz z różnymi typami modeli, ustaw parametr type na 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);
}
}
Potem skończyliśmy! Jednak jedna rzecz wspomnieć: Obiekt SortedListAdapternie posiada te same add(), remove()lub replaceAll()metod nasz oryginalny ExampleAdaptermieliśmy. Używa osobnego Editorobiektu do modyfikowania pozycji na liście, do których można uzyskać dostęp za pomocą edit()metody. Jeśli więc chcesz usunąć lub dodać elementy, do których musisz zadzwonić, edit()dodaj i usuń elementy w tym Editorwystąpieniu, a gdy skończysz, zadzwoń commit(), aby zastosować zmiany do SortedList:
mAdapter.edit()
.remove(modelToRemove)
.add(listOfModelsToAdd)
.commit();
Wszystkie zmiany wprowadzane w ten sposób są grupowane w celu zwiększenia wydajności. replaceAll()Metoda wdrożyliśmy w powyższych rozdziałach jest również obecny na tym Editorobiekcie:
mAdapter.edit()
.replaceAll(mModels)
.commit();
Jeśli zapomnisz zadzwonić, commit()żadna ze zmian nie zostanie zastosowana!