Android データ バインディングは、ObservableList を含むいくつかの Observable データ インターフェースを提供します。ただし、SortedList (RecyclerView ライブラリの最近のバージョンで導入された) は List をまったく拡張しません。
AndroidデータバインディングライブラリでRecyclerViewにSortedListを使用するにはどうすればよいですか?
Android データ バインディングは、ObservableList を含むいくつかの Observable データ インターフェースを提供します。ただし、SortedList (RecyclerView ライブラリの最近のバージョンで導入された) は List をまったく拡張しません。
AndroidデータバインディングライブラリでRecyclerViewにSortedListを使用するにはどうすればよいですか?
George Mount に触発されて、ObservableSortedList のバージョンを元の SortedList の完全な機能を実装しました。
完全なコード:
public class ObservableSortedList<T> extends AbstractList<T> implements ObservableList<T> {
/** @see android.support.v7.util.SortedList.Callback */
public interface Callback<T2> {
/** @see android.support.v7.util.SortedList.Callback#compare(Object, Object) */
int compare(T2 o1, T2 o2);
/** @see android.support.v7.util.SortedList.Callback#areItemsTheSame(Object, Object) */
boolean areItemsTheSame(T2 item1, T2 item2);
/** @see android.support.v7.util.SortedList.Callback#areContentsTheSame(Object, Object) */
boolean areContentsTheSame(T2 oldItem, T2 newItem);
}
public ObservableSortedList(final Class<T> klass, final Callback<T> callback) {
mList = new SortedList<>(klass, new CallbackWrapper<>(callback));
}
/** @see SortedList#beginBatchedUpdates() */
public void beginBatchedUpdates() { mList.beginBatchedUpdates(); }
/** @see SortedList#endBatchedUpdates() */
public void endBatchedUpdates() { mList.endBatchedUpdates(); }
@Override public boolean add(final T item) {
sTlsUpdated.set(false);
mList.add(item);
return sTlsUpdated.get(); // May be set by Callback.onInserted() or onChanged().
}
@Override public T set(final int location, final T object) {
final T old = mList.get(location);
mList.updateItemAt(location, cast(object));
return old;
}
@Override public int indexOf(final Object object) {
try {
return mList.indexOf(cast(object));
} catch (final ClassCastException ignored) {
return -1;
}
}
@Override public boolean remove(final Object object) {
try {
return mList.remove(cast(object));
} catch (final ClassCastException ignored) {
return false;
}
}
@SuppressWarnings("unchecked") private T cast(final Object object) { return (T) object; }
@Override public boolean contains(final Object object) { return indexOf(object) != SortedList.INVALID_POSITION; }
@Override public T get(final int location) { return mList.get(location); }
@Override public int size() { return mList.size(); }
@Override public void clear() { mList.clear(); }
@Override public T remove(final int location) { return mList.removeItemAt(location); }
/* ObservableList */
@Override public void addOnListChangedCallback(final OnListChangedCallback<? extends ObservableList<T>> callback) {
if (mListeners == null) this.mListeners = new ListChangeRegistry();
mListeners.add(callback);
}
@Override public void removeOnListChangedCallback(final OnListChangedCallback<? extends ObservableList<T>> callback) {
if (mListeners == null) return;
mListeners.remove(callback);
}
private final SortedList<T> mList;
private static final ThreadLocal<Boolean> sTlsUpdated = new ThreadLocal<>();
private transient @Nullable ListChangeRegistry mListeners = new ListChangeRegistry();
public class CallbackWrapper<T2> extends SortedList.Callback<T2> {
@Override public final void onInserted(final int position, final int count) {
sTlsUpdated.set(true);
if (mListeners != null) mListeners.notifyInserted(ObservableSortedList.this, position, count);
}
@Override public final void onRemoved(final int position, final int count) {
if (mListeners != null) mListeners.notifyRemoved(ObservableSortedList.this, position, count);
}
@Override public final void onMoved(final int fromPosition, final int toPosition) {
if (mListeners != null) mListeners.notifyMoved(ObservableSortedList.this, fromPosition, toPosition, 1);
}
@Override public final void onChanged(final int position, final int count) {
sTlsUpdated.set(true);
if (mListeners != null) mListeners.notifyChanged(ObservableSortedList.this, position, count);
}
@Override public int compare(final T2 o1, final T2 o2) { return mCallback.compare(o1, o2); }
@Override public boolean areContentsTheSame(final T2 oldItem, final T2 newItem) { return mCallback.areContentsTheSame(oldItem, newItem); }
@Override public boolean areItemsTheSame(final T2 item1, final T2 item2) { return mCallback.areItemsTheSame(item1, item2); }
public CallbackWrapper(final Callback<T2> callback) { mCallback = callback; }
private final Callback<T2> mCallback;
}
}
SortedList がデータ バインディングで Observability をサポートするようにするには、インターフェイスを自分で実装する必要があります。API に競合があるため、ラップする必要があるようです。このようなもの:
public class ObservableSortedList<T> implements ObservableList<T> {
private final SortedList<T> mList;
private final ListChangeRegistry mListeners = new ListChangeRegistry();
@Override
public boolean add(T item) {
int index = mList.add(item);
mListeners.notifyInserted(this, index, 1);
}
@Observable
public void addOnListChangedCallback(OnListChangedCallback<? extends ObservableList<T>> callback) {
mListeners.add(callback);
}
...
}