Last active
November 16, 2020 05:33
-
-
Save xaverkapeller/1b6233e99c6b7d54c204e61c1c9c0bf3 to your computer and use it in GitHub Desktop.
Implementation of a RecyclverView Adapter base class which uses a SortedList internally
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.content.Context; | |
import android.support.v7.util.SortedList; | |
import android.support.v7.widget.RecyclerView; | |
import android.view.LayoutInflater; | |
import android.view.View; | |
import android.view.ViewGroup; | |
import java.util.ArrayList; | |
import java.util.Collections; | |
import java.util.Comparator; | |
import java.util.List; | |
/** | |
* Created with Android Studio | |
* User: Xaver | |
* Date: 13/08/16 | |
*/ | |
public abstract class SortedListAdapter<T extends SortedListAdapter.ViewModel> extends RecyclerView.Adapter<SortedListAdapter.ViewHolder<? extends T>> { | |
public interface Editor<T extends ViewModel> { | |
Editor<T> add(T item); | |
Editor<T> add(List<T> items); | |
Editor<T> remove(T item); | |
Editor<T> remove(List<T> items); | |
Editor<T> replaceAll(List<T> items); | |
Editor<T> removeAll(); | |
void commit(); | |
} | |
public interface Filter<T> { | |
boolean test(T item); | |
} | |
private final LayoutInflater mInflater; | |
private final SortedList<T> mSortedList; | |
private final Comparator<T> mComparator; | |
public SortedListAdapter(Context context, Class<T> itemClass, Comparator<T> comparator) { | |
mInflater = LayoutInflater.from(context); | |
mComparator = comparator; | |
mSortedList = new SortedList<>(itemClass, new SortedList.Callback<T>() { | |
@Override | |
public int compare(T a, T 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(T oldItem, T newItem) { | |
return SortedListAdapter.this.areItemContentsTheSame(oldItem, newItem); | |
} | |
@Override | |
public boolean areItemsTheSame(T item1, T item2) { | |
return SortedListAdapter.this.areItemsTheSame(item1, item2); | |
} | |
}); | |
} | |
@Override | |
public final ViewHolder<? extends T> onCreateViewHolder(ViewGroup parent, int viewType) { | |
return onCreateViewHolder(mInflater, parent, viewType); | |
} | |
protected abstract ViewHolder<? extends T> onCreateViewHolder(LayoutInflater inflater, ViewGroup parent, int viewType); | |
protected abstract boolean areItemsTheSame(T item1, T item2); | |
protected abstract boolean areItemContentsTheSame(T oldItem, T newItem); | |
@Override | |
public final void onBindViewHolder(ViewHolder<? extends T> holder, int position) { | |
final T item = mSortedList.get(position); | |
((ViewHolder<T>) holder).bind(item); | |
} | |
public final Editor<T> edit() { | |
return new EditorImpl(); | |
} | |
public final T getItem(int position) { | |
return mSortedList.get(position); | |
} | |
@Override | |
public final int getItemCount() { | |
return mSortedList.size(); | |
} | |
public final List<T> filter(Filter<T> filter) { | |
final List<T> list = new ArrayList<>(); | |
for (int i = 0, count = mSortedList.size(); i < count; i++) { | |
final T item = mSortedList.get(i); | |
if (filter.test(item)) { | |
list.add(item); | |
} | |
} | |
return list; | |
} | |
public final T filterOne(Filter<T> filter) { | |
for (int i = 0, count = mSortedList.size(); i < count; i++) { | |
final T item = mSortedList.get(i); | |
if (filter.test(item)) { | |
return item; | |
} | |
} | |
return null; | |
} | |
private interface Action<T extends ViewModel> { | |
void perform(SortedList<T> list); | |
} | |
private class EditorImpl implements Editor<T> { | |
private final List<Action<T>> mActions = new ArrayList<>(); | |
@Override | |
public Editor<T> add(final T item) { | |
mActions.add(new Action<T>() { | |
@Override | |
public void perform(SortedList<T> list) { | |
mSortedList.add(item); | |
} | |
}); | |
return this; | |
} | |
@Override | |
public Editor<T> add(final List<T> items) { | |
mActions.add(new Action<T>() { | |
@Override | |
public void perform(SortedList<T> list) { | |
Collections.sort(items, mComparator); | |
mSortedList.addAll(items); | |
} | |
}); | |
return this; | |
} | |
@Override | |
public Editor<T> remove(final T item) { | |
mActions.add(new Action<T>() { | |
@Override | |
public void perform(SortedList<T> list) { | |
mSortedList.remove(item); | |
} | |
}); | |
return this; | |
} | |
@Override | |
public Editor<T> remove(final List<T> items) { | |
mActions.add(new Action<T>() { | |
@Override | |
public void perform(SortedList<T> list) { | |
for (T item : items) { | |
mSortedList.remove(item); | |
} | |
} | |
}); | |
return this; | |
} | |
@Override | |
public Editor<T> replaceAll(final List<T> items) { | |
mActions.add(new Action<T>() { | |
@Override | |
public void perform(SortedList<T> list) { | |
final List<T> itemsToRemove = filter(new Filter<T>() { | |
@Override | |
public boolean test(T item) { | |
return !items.contains(item); | |
} | |
}); | |
for (int i = itemsToRemove.size() - 1; i >= 0; i--) { | |
final T item = itemsToRemove.get(i); | |
mSortedList.remove(item); | |
} | |
mSortedList.addAll(items); | |
} | |
}); | |
return this; | |
} | |
@Override | |
public Editor<T> removeAll() { | |
mActions.add(new Action<T>() { | |
@Override | |
public void perform(SortedList<T> list) { | |
mSortedList.clear(); | |
} | |
}); | |
return this; | |
} | |
@Override | |
public void commit() { | |
mSortedList.beginBatchedUpdates(); | |
for (Action<T> action : mActions) { | |
action.perform(mSortedList); | |
} | |
mSortedList.endBatchedUpdates(); | |
mActions.clear(); | |
} | |
} | |
public abstract static class ViewHolder<T extends ViewModel> extends RecyclerView.ViewHolder { | |
private T mCurrentItem; | |
public ViewHolder(View itemView) { | |
super(itemView); | |
} | |
public final void bind(T item) { | |
mCurrentItem = item; | |
performBind(item); | |
} | |
protected abstract void performBind(T item); | |
public final T getCurrentItem() { | |
return mCurrentItem; | |
} | |
} | |
public interface ViewModel { | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Is it possible to make mComparator not final ? I would like to let people switch order type.