Skip to content

Instantly share code, notes, and snippets.

@henrytao-me
Created October 16, 2016 12:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save henrytao-me/b5ba794e5fd2a3e4cfc79e446cbf21e9 to your computer and use it in GitHub Desktop.
Save henrytao-me/b5ba794e5fd2a3e4cfc79e446cbf21e9 to your computer and use it in GitHub Desktop.
/*
* Copyright 2016 "Henry Tao <hi@henrytao.me>"
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package me.henrytao.shopifyblogandroid.util;
import android.support.annotation.NonNull;
import android.support.v7.util.DiffUtil;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import me.henrytao.mvvmlifecycle.MVVMObserver;
import me.henrytao.mvvmlifecycle.recyclerview.RecyclerViewBindingAdapter;
import me.henrytao.mvvmlifecycle.recyclerview.RecyclerViewBindingViewHolder;
import me.henrytao.mvvmlifecycle.rx.SubscriptionUtils;
import me.henrytao.mvvmlifecycle.rx.Transformer;
import rx.Observable;
/**
* Created by henrytao on 9/29/16.
*/
public class DiffRecyclerViewBindingAdapter<D, V extends RecyclerViewBindingViewHolder<D>> extends RecyclerViewBindingAdapter<D, V> {
private final DataComparable<D> mComparable;
private final List<D> mShadowData;
public DiffRecyclerViewBindingAdapter(Class<V> clsView, MVVMObserver observer, @NonNull List<D> shadowData,
DataComparable<D> comparable) {
super(clsView, observer, new ArrayList<>());
mShadowData = shadowData;
mComparable = comparable;
}
public void applyDiff() {
applyDiff(true);
}
public Observable<Void> calculateDiff() {
Observable<DiffUtil.DiffResult> observable = Observable.create(subscriber -> {
try {
DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new DiffUtilCallback<>(mComparable, mData, mShadowData));
SubscriptionUtils.onNextAndComplete(subscriber, diffResult);
} catch (Exception exception) {
SubscriptionUtils.onError(subscriber, exception);
}
});
return observable.flatMap(this::applyDiff).map(o -> null);
}
private void applyDiff(boolean shouldNotifyDataSetChanged) {
mData.clear();
mData.addAll(mShadowData);
if (shouldNotifyDataSetChanged) {
notifyDataSetChanged();
}
}
private Observable<Void> applyDiff(DiffUtil.DiffResult diffResult) {
Observable<Void> observable = Observable.create(subscriber -> {
applyDiff(false);
diffResult.dispatchUpdatesTo(this);
SubscriptionUtils.onComplete(subscriber);
});
return observable.compose(Transformer.applyMainThreadScheduler());
}
public interface DataComparable<D> extends ItemComparable<D> {
boolean areContentsTheSame(D oldData, D newData);
}
public interface ItemComparable<D> {
boolean areItemsTheSame(D oldData, D newData);
}
public static class DiffArrayList<D> extends ArrayList<D> {
private final ItemComparable<D> mComparable;
public DiffArrayList(@NonNull ItemComparable<D> comparable, int capacity) {
super(capacity);
mComparable = comparable;
}
public DiffArrayList(@NonNull ItemComparable<D> comparable) {
mComparable = comparable;
}
public DiffArrayList(@NonNull ItemComparable<D> comparable, Collection<? extends D> collection) {
super(collection);
mComparable = comparable;
}
@Override
public boolean add(D object) {
int existedIndex = indexOfWithComparable(object);
if (existedIndex >= 0) {
set(existedIndex, object);
return true;
}
return super.add(object);
}
@Override
public void add(int index, D object) {
int existedIndex = indexOfWithComparable(object);
if (existedIndex >= 0) {
set(existedIndex, object);
} else {
super.add(index, object);
}
}
@SuppressWarnings("unchecked")
@Override
public boolean addAll(Collection<? extends D> collection) {
Object[] newPart = collection.toArray();
for (Object object : newPart) {
add((D) object);
}
return true;
}
@SuppressWarnings("unchecked")
@Override
public boolean addAll(int index, Collection<? extends D> collection) {
Object[] newPart = collection.toArray();
int i = newPart.length - 1;
while (i >= 0) {
add(index, (D) newPart[i]);
i--;
}
return true;
}
@SuppressWarnings("unchecked")
@Override
public boolean remove(Object object) {
try {
int index = indexOfWithComparable((D) object);
if (index >= 0) {
remove(index);
}
} catch (ClassCastException ignore) {
return false;
}
return true;
}
private int indexOfWithComparable(D object) {
int size = size();
for (int i = 0; i < size; i++) {
if (mComparable.areItemsTheSame(object, get(i))) {
return i;
}
}
return -1;
}
}
private static class DiffUtilCallback<D> extends DiffUtil.Callback {
private final DataComparable<D> mDataComparable;
private final List<D> mNewData;
private final List<D> mOldData;
private DiffUtilCallback(DataComparable<D> dataComparable, List<D> oldData, List<D> newData) {
mOldData = oldData;
mNewData = newData;
mDataComparable = dataComparable;
}
@Override
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
return mDataComparable.areContentsTheSame(mOldData.get(oldItemPosition), mNewData.get(newItemPosition));
}
@Override
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
return mDataComparable.areItemsTheSame(mOldData.get(oldItemPosition), mNewData.get(newItemPosition));
}
@Override
public int getNewListSize() {
return mNewData.size();
}
@Override
public int getOldListSize() {
return mOldData.size();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment