Myers差分算法在首页中的应用

从DiffUtil到Myers差量分析算法

Posted by Tristan on April 19, 2019

背景

首页列表变量更新,首页的上半身是个列表,列表根据变化内容刷新是必要的;但如果全量更新,则会产生不必要的性能损耗。通常,用户的每多一次下拉刷新,首页区块都无需更新。
搭建基础diff工具类,diff的应用场景很广泛,两组字符串、两个列表之间有何变化都可能需要做diff分析,平台有必要搭建这样一个不受限于业务和具体UI控件的工具类供业务方使用。

Diff工具类

Android中的diff工具类已经存在,比如下面两个:

DiffUtil

DiffUtil,用于比较两个数据集,寻找出旧数据集->新数据集的最小变化量。

它的出现满足了数据集变量更新的诉求,并填补了RecyclerView的以下缺陷:

  1. 如果使用notifyDataSetChanged()全量更新数据,性能则会变差,同时变更动画将失效
  2. 如果使用notifyItemRangeXxx()变量更新数据,成本则会增大,因为业务层需要计算出变更的数据项

AsyncListDiffer

AsyncListDiffer,它是DiffUtil的进化版,在后台线程使用DiffUtil计算diff的最小量,同时又在主线程中将更新操作的最小量分发给ListUpdateCallback,以完成数据更新,从而弥补了DiffUtil的缺陷。

那么已经有了如此好的工具,我们直接用于首页列表的diff可不可以呢?

“可以”;但是,DiffUtil存在弊端,其内部引用了RecyclerView的Adapter,与View层产生高度耦合。作为工具类,这种设计是过度封装的,不好扩展和移植。

此时,我们也想进一步了解DiffUtil的实现机制,考虑做一个与View层无耦合的diff工具类,这样可以更好地进行代码扩展和移植。

DiffUtil的算法

Diff的核心是差分算法,DiffUtil的算法则是著名的Myers差分算法。它有两个特性:

  1. 计算出了最小的变化量,而且随变化量越小时间复杂度越低
  2. 直观,计算出的变化内容看起来要比其他算法更容易理解

Myers算法原理及推导

推导

图形解释

“直观”是Myers的特性

  1. Git生成diff为什么会用到Myers

    首页列表的diff

参考文献

The Myers diff algorithm: part 1