{"id":16558338,"url":"https://github.com/leifzhang/diffutils","last_synced_at":"2025-03-21T10:32:34.723Z","repository":{"id":41882196,"uuid":"189940249","full_name":"Leifzhang/DiffUtils","owner":"Leifzhang","description":"通过Parcel copy的方式深copy数据  DiffUtil抽象","archived":false,"fork":false,"pushed_at":"2022-08-09T04:02:57.000Z","size":273,"stargazers_count":37,"open_issues_count":0,"forks_count":7,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-18T00:43:39.208Z","etag":null,"topics":["diffutil","recyclerview"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Leifzhang.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-06-03T05:29:45.000Z","updated_at":"2025-01-13T08:04:42.000Z","dependencies_parsed_at":"2022-08-11T20:00:59.043Z","dependency_job_id":null,"html_url":"https://github.com/Leifzhang/DiffUtils","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Leifzhang%2FDiffUtils","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Leifzhang%2FDiffUtils/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Leifzhang%2FDiffUtils/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Leifzhang%2FDiffUtils/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Leifzhang","download_url":"https://codeload.github.com/Leifzhang/DiffUtils/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244778051,"owners_count":20508846,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["diffutil","recyclerview"],"created_at":"2024-10-11T20:10:26.170Z","updated_at":"2025-03-21T10:32:34.373Z","avatar_url":"https://github.com/Leifzhang.png","language":"Kotlin","readme":"# DiffUtils\n\n## 背景以及原理\n\n谷歌在封装RecyclerView时候建议我们最好不要去调用`notifyDataSetChanged`，而是去调用其他的局部刷新的方法（增删改）。但是由于要计算游标等等所以感觉其实非常不好用，而且可能会导致一些奇奇怪怪的crash问题。\n\n而DiffUtils的使用，首先要有两个List，一个代表旧数据，一个代表新数据，内部旧涉及到数据copy的问题，如果浅拷贝的话，其equals比较是没有任何意义的，所以项目使用了深拷贝的形式。\n\n原理基于Parcel，用安卓原生的Parcelable进行数据模型拷贝。\n\n当前项目简单的diffutil封装以及配合recyclerview adapter使用，可以实现数据动态增删移动等等操作同时配合，recyclerview adapter的局部数据调整刷新结合在一起。\n\n## 使用\n\n代码已经加入了线程池，以及主线程调度逻辑，所以可以直接子线程使用。不上传maven的原因是觉得可能还不够完善，可以直接考虑代码复制。\n\n1. 对代码进行了重定义封装，当你需要使用深拷贝的时候，切记实现Parcelable接口，数据model最好实现IDifference接口，根据这个进行数据ID逻辑判断。如果要做内容比较的情况下实现IEqualsAdapter，同时使用插件生成hashcode，equals方法。\n   \n\n```kotlin\ndata class TestEntity(var id: Int = 0,\n                      var displayTime: Long = 0,\n                      var text: String? = Random().nextInt(10000).toString()) : Parcelable, IDifference, IEqualsAdapter {\n\n    override val uniqueId: String\n        get() = id.toString()\n\n    fun update() {\n        displayTime = System.currentTimeMillis()\n        text = \"更新数据\"\n    }\n\n    constructor(source: Parcel) : this(\n            source.readInt(),\n            source.readLong(),\n            source.readString()\n    )\n\n    override fun describeContents() = 0\n\n    override fun writeToParcel(dest: Parcel, flags: Int) = with(dest) {\n        writeInt(id)\n        writeLong(displayTime)\n        writeString(text)\n    }\n\n    companion object {\n        @JvmField\n        val CREATOR: Parcelable.Creator\u003cTestEntity\u003e = object : Parcelable.Creator\u003cTestEntity\u003e {\n            override fun createFromParcel(source: Parcel): TestEntity = TestEntity(source)\n            override fun newArray(size: Int): Array\u003cTestEntity?\u003e = arrayOfNulls(size)\n        }\n    }\n}\n```\n\n2. 初始化并传入数据，并设置数据刷新回掉，如果你有header或者别的话自己定义一个,提供了深拷贝和浅拷贝的两种实现。\n\n```kotlin\n     // 深拷贝\n     val diffHelper: ParcelDiffHelper\u003cTestEntity\u003e = ParcelDiffHelper()\n     diffHelper.callBack = SimpleAdapterCallBack(this)\n     // lifecyclerowner \n     diffHelper.bindLifeCycle(this)\n     diffHelper.setData(items)\n```\n\n```kotlin\n    //浅拷贝版本\n     val diffHelper: SimpleDiffHelper\u003cString\u003e = SimpleDiffHelper()\n     diffHelper.callBack = SimpleAdapterCallBack(this)\n     // lifecyclerowner \n     diffHelper.bindLifeCycle(this)\n     diffHelper.setData(items)\n```\n\n3. 当items发生变化(任意变化增删改都行)，调用数据刷新。\n\n```kotlin\n   diffHelper.notifyItemChanged()\n```\n\n## 其他\n\n代码可以结合任意的Adapter使用，包括BRVH等等。Demo中有简单的接入方式。","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleifzhang%2Fdiffutils","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fleifzhang%2Fdiffutils","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleifzhang%2Fdiffutils/lists"}