import android.support.v7.util.DiffUtil; import java.util.List; import rx.Observable; import rx.functions.Func2; public class RxDiffUtil { public static Observable.Transformer> diff(final Callback callback) { return diff(callback, true); } public static Observable.Transformer> diff(final Callback callback, final boolean detectMoves) { return new Observable.Transformer>() { @Override public Observable> call(Observable observable) { return observable.reduce(null, new Func2, T, Result>() { @Override public Result call(Result oldResult, T newItems) { if (oldResult == null) { return new Result<>(newItems, DiffUtil.calculateDiff(new FirstDiffCallback<>(callback, newItems), detectMoves)); } else { return new Result<>(newItems, DiffUtil.calculateDiff(new DiffCallback<>(callback, oldResult.items, newItems), detectMoves)); } } }); } }; } public static > Observable.Transformer, Result>> diff(boolean detectMoves) { return diff(new DiffableListCallback(), detectMoves); } public static > Observable.Transformer, Result>> diff() { return diff(true); } public interface Diffable { boolean isSame(T other); } public static class Result { public final T items; public final DiffUtil.DiffResult diff; public Result(T items, DiffUtil.DiffResult diff) { this.items = items; this.diff = diff; } } public static abstract class Callback { public abstract int getSize(T list); public abstract boolean areItemsTheSame(int oldItemPosition, T oldItems, int newItemPosition, T newItems); public abstract boolean areContentsTheSame(int oldItemPosition, T oldItems, int newItemPosition, T newItems); } public static abstract class ListCallback extends Callback> { @Override public int getSize(List list) { return list.size(); } @Override public final boolean areItemsTheSame(int oldItemPosition, List oldItems, int newItemPosition, List newItems) { return areItemsTheSame(oldItems.get(oldItemPosition), newItems.get(newItemPosition)); } @Override public final boolean areContentsTheSame(int oldItemPosition, List oldItems, int newItemPosition, List newItems) { return areContentsTheSame(oldItems.get(oldItemPosition), newItems.get(newItemPosition)); } public abstract boolean areItemsTheSame(T oldItem, T newItem); public abstract boolean areContentsTheSame(T oldItem, T newItem); } public static class DiffableListCallback> extends ListCallback { @Override public boolean areItemsTheSame(T oldItem, T newItem) { return oldItem.isSame(newItem); } @Override public boolean areContentsTheSame(T oldItem, T newItem) { return oldItem.equals(newItem); } } private static class FirstDiffCallback extends DiffUtil.Callback { private final Callback callback; private final T newItems; FirstDiffCallback(Callback callback, T newItems) { this.callback = callback; this.newItems = newItems; } @Override public int getOldListSize() { return 0; } @Override public int getNewListSize() { return callback.getSize(newItems); } @Override public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) { return false; } @Override public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { return false; } } private static class DiffCallback extends DiffUtil.Callback { private final Callback callback; private final T oldItems; private final T newItems; DiffCallback(Callback callback, T oldItems, T newItems) { this.callback = callback; this.oldItems = oldItems; this.newItems = newItems; } @Override public int getOldListSize() { return callback.getSize(oldItems); } @Override public int getNewListSize() { return callback.getSize(newItems); } @Override public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) { return callback.areContentsTheSame(oldItemPosition, oldItems, newItemPosition, newItems); } @Override public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { return callback.areContentsTheSame(oldItemPosition, oldItems, newItemPosition, newItems); } } }