Android DiffUtil

  Android 的recyclerview-v7:24.2.0 发布后多了个DiffUtil工具类,这个工具类能够大大解放了Android开发者的一个苦恼:RecyclerView局部刷新和重新刷新时实际只改变了部分数据。

  DiffUtil能够计算两个列表之间的差值,并计算出旧列表变换到新列表的过程(DiffResult),DiffResult可以直接应用到RecyclerView的Adapter中,DiffResult会使用Adapter的notifyItemRangeChanged等方法来更新RecyclerView。

  DiffUtil使用了Eugene W.Myers's difference algorithm 去计算从旧集合到新集合的最小更新序列,Myers 算法并没有处理集合中的子项偏移情况,所以如果选择了要计算偏移情况的话,需要进行第二次的运算来检查子项偏移,所以会产生更多的计算时间成本。当集合的数据量较大时,Myers算法的处理时间会较长,所以不要在集合数据量大时在主线程进行Diff运算,应该放在后台线程中进行运算,将运算结果(DiffResult)在主线程进行更新RecyclerView。需要值得注意的是,子项偏移的运算会比较明显得增加Diff时间,所以在集合默认是排序情况下,关闭该功能。

  DiffUtil的Demo可以在网络上其他地方找到,这里不再赘述,只简单提下大致使用方法。

1、calculateDiff是最核心的方法,Callback并不是我们常见的回调,更准确点说应该是一个策略

DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(DiffUtil.Callback, boolean);

2、DiffUtil.Callback可实现的方法,DiffUtil会对每个position调用对应的方法,我们只需要在Callback中告诉DiffUtil,在哪个位置中,如何判别两个列表在这个位置是否是同一个子项,如果是,有没有局部变化,如果有局部变化,都变了哪里?DiffUtil只需要知道这些,就可以计算出DiffResult

/**
     * A Callback class used by DiffUtil while calculating the diff between two lists.
     */
    public abstract static class Callback {
        /**
         * Returns the size of the old list.
         *
         * @return The size of the old list.
         */
        public abstract int getOldListSize();

        /**
         * Returns the size of the new list.
         *
         * @return The size of the new list.
         */
        public abstract int getNewListSize();

        /**
         * Called by the DiffUtil to decide whether two object represent the same Item.
         * <p>
         * For example, if your items have unique ids, this method should check their id equality.
         *
         * @param oldItemPosition The position of the item in the old list
         * @param newItemPosition The position of the item in the new list
         * @return True if the two items represent the same object or false if they are different.
         */
        public abstract boolean areItemsTheSame(int oldItemPosition, int newItemPosition);

        /**
         * Called by the DiffUtil when it wants to check whether two items have the same data.
         * DiffUtil uses this information to detect if the contents of an item has changed.
         * <p>
         * DiffUtil uses this method to check equality instead of {@link Object#equals(Object)}
         * so that you can change its behavior depending on your UI.
         * For example, if you are using DiffUtil with a
         * {@link android.support.v7.widget.RecyclerView.Adapter RecyclerView.Adapter}, you should
         * return whether the items' visual representations are the same.
         * <p>
         * This method is called only if {@link #areItemsTheSame(int, int)} returns
         * {@code true} for these items.
         *
         * @param oldItemPosition The position of the item in the old list
         * @param newItemPosition The position of the item in the new list which replaces the
         *                        oldItem
         * @return True if the contents of the items are the same or false if they are different.
         */
        public abstract boolean areContentsTheSame(int oldItemPosition, int newItemPosition);

        /**
         * When {@link #areItemsTheSame(int, int)} returns {@code true} for two items and
         * {@link #areContentsTheSame(int, int)} returns false for them, DiffUtil
         * calls this method to get a payload about the change.
         * <p>
         * For example, if you are using DiffUtil with {@link RecyclerView}, you can return the
         * particular field that changed in the item and your
         * {@link android.support.v7.widget.RecyclerView.ItemAnimator ItemAnimator} can use that
         * information to run the correct animation.
         * <p>
         * Default implementation returns {@code null}.
         *
         * @param oldItemPosition The position of the item in the old list
         * @param newItemPosition The position of the item in the new list
         *
         * @return A payload object that represents the change between the two items.
         */
        @Nullable
        public Object getChangePayload(int oldItemPosition, int newItemPosition) {
            return null;
        }
    }

 3、DiffResult应用到RecyclerView的Adapter.

 DiffResult.dispatchUpdatesTo(RecyclerView.Adapter);

 4、关于Adapter以前的一个知识点,payloads,可能有些朋友还不知道Adapter还有一个onBindViewHolder重载方法,比常见的onBindViewHolder多一个参数:List<Object> payloads。当DiffResult中有某一项出现两个列表实际上在该位置是同一个子项,但是发生了局部变化,则调用该重载方法时带上payloads,payloads中的对象可以在Callback的getChangePayload给定。payloads不会为null,所以检查payloads是否为空,为空,直接调用默认的onBindViewHolder即可。

public void onBindViewHolder(StudentViewHolder holder, int position, List<Object> payloads) {}

  

 

  

posted on 2016-10-09 12:23 厌世夕阳 阅读( ...) 评论( ...) 编辑 收藏

转载于:https://www.cnblogs.com/recwert/p/5941676.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android 中,DiffUtil 是一个非常有用的工具类,可以帮助我们避免整个 RecyclerView 的刷新,只需要刷新发生化的部分即可。下面介绍一下如何在低版本的 Android 系统中使用 DiffUtil: 1. 添加依赖库 在项目的 build.gradle 文件中,添加以下依赖库: ``` dependencies { implementation "androidx.recyclerview:recyclerview:版本号" } ``` 2. 创建 DiffUtil.Callback 实现类 创建一个实现 DiffUtil.Callback 接口的类,该接口有四个方法需要实现: - getOldListSize():返回旧数据集合的大小。 - getNewListSize():返回新数据集合的大小。 - areItemsTheSame():判断两个数据是否是同一个对象。 - areContentsTheSame():判断两个数据内容是否相同。 例如: ``` class MyDiffCallback(private val oldList: List<String>, private val newList: List<String>) : DiffUtil.Callback() { override fun getOldListSize(): Int { return oldList.size } override fun getNewListSize(): Int { return newList.size } override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { return oldList[oldItemPosition] == newList[newItemPosition] } override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { return oldList[oldItemPosition] == newList[newItemPosition] } } ``` 3. 调用 DiffUtil.calculateDiff() 方法 在需要更新数据的地方,创建一个 DiffUtil.Callback 实例,并调用 DiffUtil.calculateDiff() 方法,该方法会返回一个 DiffUtil.DiffResult 实例,我们可以在该实例的 dispatchUpdatesTo() 方法中调用 RecyclerView.Adapter.notifyItemRangeChanged() 方法来更新 RecyclerView 中的数据。 例如: ``` val diffCallback = MyDiffCallback(oldList, newList) val diffResult = DiffUtil.calculateDiff(diffCallback) diffResult.dispatchUpdatesTo(adapter) ``` 通过以上步骤,我们就可以在低版本的 Android 系统中使用 DiffUtil 来避免整个 RecyclerView 的刷新,只需要刷新发生化的部分即可。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值