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/menu
utwórz nowy plik o nazwie main_menu.xml
. W niej dodać element i ustawić actionViewClass
się android.support.v7.widget.SearchView
. Ponieważ korzystasz z biblioteki wsparcia, musisz użyć przestrzeni nazw biblioteki wsparcia, aby ustawić actionViewClass
atrybut. 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 Fragment
lub Activity
musisz napompować to menu xml jak zwykle, możesz poszukać, MenuItem
który zawiera SearchView
i zaimplementować, OnQueryTextListener
któ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 SearchView
jest 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 ViewHolder
dla ExampleModel
klasy:
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ę Adapter
i zamiast tego skoncentruję się na częściach, które są istotne dla tej odpowiedzi.
Ale najpierw jest jedna rzecz, o której musimy porozmawiać: SortedList
klasa.
SortedList
SortedList
Jest zupełnie niesamowite narzędzie, które jest częścią RecyclerView
biblioteki. Dba o powiadamianie Adapter
o 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 SortedList
taki sam sposób jak Comparator
. Ale zamiast sortowania List
służy do sortowania elementów w RecyclerView
!
W SortedList
współdziała z Adapter
za pośrednictwem Callback
klasy, 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
, onInserted
itp trzeba nazwać odpowiednikiem zawiadomić sposób dokonania Adapter
. Trzy sposoby na dole compare
, areContentsTheSame
i areItemsTheSame
trzeba 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, Comparator
któ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 SortedList
używa tego, aby ustalić, czy zdarzenie zmiana musi być wywoływany - innymi słowy, czy RecyclerView
należ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();
}
SortedList
Korzysta z tej metody, aby sprawdzić, czy dwie pozycje odnoszą się do tego samego. Mówiąc najprościej (bez wyjaśnienia, jak SortedList
działa), służy to do ustalenia, czy obiekt jest już zawarty List
i 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.Callback
poprawnie zaimplementowanemu możemy utworzyć instancję SortedList
:
final SortedList<ExampleModel> list = new SortedList<>(ExampleModel.class, mCallback);
Jako pierwszy parametr w konstruktorze SortedList
musisz przekazać klasę swoich modeli. Drugi parametr to po prostu SortedList.Callback
zdefiniowany powyżej.
Przejdźmy teraz do rzeczy : jeśli zaimplementujemy Adapter
z 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();
}
}
Comparator
Uż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, Adapter
któ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ż SortedList
już to robi za pośrednictwem SortedList.Callback
! Poza tym implementacja tych metod jest dość prosta, z jednym wyjątkiem: metodą remove, która usuwa List
modele. Ponieważ SortedList
ma 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 SortedList
razem 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 SortedList
już znajduje się w SortedList
nim, nie zostanie dodany ponownie. Zamiast tego SortedList
używa tej areContentsTheSame()
metody, aby dowiedzieć się, czy obiekt się zmienił - a jeśli ma element w, RecyclerView
zostanie zaktualizowany.
W każdym razie to, co zwykle wolę, to jedna metoda, która pozwala mi na zastąpienie wszystkich przedmiotów RecyclerView
naraz. Usuń wszystko, czego nie ma w, List
i 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 List
do za SortedList
pomocą, 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, SortedList
ale zostały zmienione.
I z tym Adapter
jest 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ć List
wszystkie możliwe modele. W tym przykładzie utworzyć List
z ExampleModel
przypadkó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ę Adapter
i ustawiamy ją na RecyclerView
. Następnie tworzymy List
modele z nazw filmów w MOVIES
tablicy. 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 List
od ExampleModel
s, a także ciąg kwerendy. Następnie zadzwoń replaceAll()
na Adapter
i przekazać w filtrowane List
zwrócony przez filter()
. Musimy również wezwać scrollToPosition(0)
do, RecyclerView
aby upewnić się, że użytkownik zawsze widzi wszystkie elementy podczas wyszukiwania czegoś. W przeciwnym razie RecyclerView
filtr 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, List
któ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 Adapter
opartym na SortedList
znacznie 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ć Adapter
klasę podstawową który już zajmuje się radzeniem sobie z SortedList
modelami ViewHolder
i ich wiązaniem z instancjami i zapewnia wygodny sposób implementacji modelu Adapter
opartego na SortedList
. W tym celu musimy zrobić dwie rzeczy:
- Musimy stworzyć
ViewModel
interfejs, który wszystkie klasy modeli muszą wdrożyć
- Musimy utworzyć
ViewHolder
podklasę, która definiuje bind()
metodę, której Adapter
można użyć do automatycznego wiązania modeli.
To pozwala nam skupić się na treści, która ma być wyświetlana po RecyclerView
prostu poprzez wdrożenie modeli i odpowiadających im ViewHolder
implementacji. Korzystając z tej klasy bazowej, nie musimy się martwić o skomplikowane szczegóły Adapter
i 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ć, SortedListAdapter
musimy wprowadzić dwie zmiany:
Zmień ViewHolder
tak, 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ą ViewModel
interfejs:
public class ExampleModel implements SortedListAdapter.ViewModel {
...
}
Następnie musimy tylko zaktualizować, ExampleAdapter
aby rozszerzyć SortedListAdapter
i 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 SortedListAdapter
nie posiada te same add()
, remove()
lub replaceAll()
metod nasz oryginalny ExampleAdapter
mieliśmy. Używa osobnego Editor
obiektu 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 Editor
wystą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 Editor
obiekcie:
mAdapter.edit()
.replaceAll(mModels)
.commit();
Jeśli zapomnisz zadzwonić, commit()
żadna ze zmian nie zostanie zastosowana!