Skip to content

Instantly share code, notes, and snippets.

@henrytao-me
Created October 16, 2016 12:32
Show Gist options
  • Select an option

  • Save henrytao-me/b5ba794e5fd2a3e4cfc79e446cbf21e9 to your computer and use it in GitHub Desktop.

Select an option

Save henrytao-me/b5ba794e5fd2a3e4cfc79e446cbf21e9 to your computer and use it in GitHub Desktop.

Revisions

  1. henrytao-me created this gist Oct 16, 2016.
    211 changes: 211 additions & 0 deletions DiffRecyclerViewBindingAdapter.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,211 @@
    /*
    * 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();
    }
    }
    }