RecyclerView与声明式(下)

247 阅读2分钟

这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战

在上文中我已经介绍RV(本文中代指RecyclerView)的一个方便的类ListAdapter,可它跟声明式有什么关系呢?这篇文章中我们一起来扒一扒代码中细节,感受一下代码中的声明式编程。

是的,在第一版代码到第二版代码中RV的操作部分实际上就是命令式到声明式的转换。

细节

在第二版代码中,我先将数据类Todo的所有属性全改为val了。

data class Todo(val id:int,val content:String,val done = false)

这意味着你修改TodoList中的一个Todo元素的任意一个属性都必须重新构建一个新的对象。好在Kotlin的数据类有个非常好用的函数copy。例如你想要修改完成状态,只需要通过下面这段代码就能实现。

val todo2 = todo1.copy(done = true)

另外,命令式的代码中是通过Adapter构造器传入的可变列表,所有的操作都是对这个可变列表进行的修改,修改数据后伴随着对RV的UI刷新。可以命令式对数据的修改和UI的修改是一起的,这样很容易就增加耦合。

而声明式中你想要做的就是把修改过的新数据给submitList函数就好,差异会由DiffUtil.ItemCallback计算出来,具体的行为ListAdapter会根据差异来执行。事实上,不可变列表以及不可变属性也是为这套流程服务的。

object diffCallback : DiffUtil.ItemCallback<Todo>() {
        override fun areItemsTheSame(oldItem: Todo, newItem: Todo): Boolean
            = oldItem.id == newItem.id

        override fun areContentsTheSame(oldItem: Todo, newItem: Todo): Boolean 
            = oldItem.content == newItem.content
              && oldItem.done == newItem.done
}

现在来解释一下diffCallback:areItemsTheSame函数比较的是同一个位置的item是否一致,内容不一致,会触发移动或者增删行为,areContentsTheSame函数比较的是一致的item的内容是否一致,内容不一致会触发item刷新的。

总结

在声明式中,RV的任何变化来自于俩个数据。准确地说是来源于俩个数据对比出来的差异。你只需要处理好你的想要的差异就够了,剩下的都会有强大的框架帮你解决。

这也就是很多人说的,命令式是你告诉程序应该做什么,而声明式是你告诉程序你想要什么。

你可能说修改一个item也要创建另一个几乎一模一样的对象,好浪费空间哟!弹你个脑瓜崩,我就问你,项目开发中你是想要一个易迭代维护的项目,还是要一个看起来很痛苦却省资源的项目?