Clockplus/app/src/main/java/com/philliphsu/clock2/BaseAdapter.java
2016-05-31 15:33:33 -07:00

101 lines
3.8 KiB
Java

package com.philliphsu.clock2;
import android.support.v7.util.SortedList;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.util.SortedListAdapterCallback;
import android.view.ViewGroup;
import java.util.List;
/**
* Created by Phillip Hsu on 5/31/2016.
*/
public abstract class BaseAdapter<T, VH extends BaseViewHolder<T>> extends RecyclerView.Adapter<VH> {
private final OnListItemInteractionListener<T> mListener;
private final SortedList<T> mItems;
protected BaseAdapter(Class<T> cls, List<T> items, OnListItemInteractionListener<T> listener) {
mItems = new SortedList<>(cls, new SortedListAdapterCallback<T>(this) {
@Override
public int compare(T o1, T o2) {
//return BaseAdapter.this.<T, VH>*compare(o1, o2); // *: See note below
return BaseAdapter.this.compare(o1, o2);
// Only need to specify the type when calling a _generic_ method
// that defines _its own type parameters_ in its signature, but even
// then, it's not actually necessary because the compiler can
// infer the type.
// This is just an _abstract_ method that takes params of type T.
}
@Override
public boolean areContentsTheSame(T oldItem, T newItem) {
return BaseAdapter.this.areContentsTheSame(oldItem, newItem);
}
@Override
public boolean areItemsTheSame(T item1, T item2) {
return BaseAdapter.this.areItemsTheSame(item1, item2);
}
});
mListener = listener;
mItems.addAll(items);
}
protected abstract VH onCreateViewHolder(ViewGroup parent, OnListItemInteractionListener<T> listener);
protected abstract int compare(T o1, T o2);
protected abstract boolean areContentsTheSame(T oldItem, T newItem);
protected abstract boolean areItemsTheSame(T item1, T item2);
@Override // not final to allow subclasses to use the viewType if needed
public VH onCreateViewHolder(ViewGroup parent, int viewType) {
return onCreateViewHolder(parent, mListener);
}
@Override
public final void onBindViewHolder(VH holder, int position) {
holder.onBind(mItems.get(position));
}
@Override
public final int getItemCount() {
return mItems.size();
}
public final void replaceData(List<T> items) {
mItems.clear();
mItems.addAll(items);
}
protected final T getItem(int position) {
return mItems.get(position);
}
public final int addItem(T item) {
return mItems.add(item);
}
public final boolean removeItem(T item) {
return mItems.remove(item);
}
public final void updateItem(T oldItem, T newItem) {
// SortedList finds the index of an item by using its callback's compare() method.
// We can describe our current item update process is as follows:
// * An item's fields are modified
// * The changes are saved to the repository
// * A item update callback is fired to the RV
// * The RV calls its adapter's updateItem(), passing the instance of the modified item as both arguments
// (because modifying an item keeps the same instance of the item)
// * The SortedList tries to find the index of the param oldItem, but since its fields are changed,
// the search may end up failing because compare() could return the wrong index.
// A workaround is to copy construct the original item instance BEFORE you modify the fields.
// Then, oldItem should point to the copied instance.
// Alternatively, a better approach is to make items immutable.
mItems.updateItemAt(mItems.indexOf(oldItem), newItem);
}
}