如何在Jetpack Compose的SnapshotStateList中使用MutableSet
在Jetpack Compose中结合MutableSet与mutableStateListOf实现唯一元素列表
方案一:手动维护Set与StateList的同步
这种方式简单直接,额外维护一个MutableSet跟踪已存在元素,在添加/移除操作时同步更新mutableStateListOf创建的列表:
// 用于记录已存在的元素,确保唯一性 private val existingResults = mutableSetOf<ScanResult>() // 供Compose使用的状态列表,会触发重组 val list by lazy { mutableStateListOf<ScanResult>() } // 添加元素:仅当元素不存在时才加入列表 fun addScanResult(result: ScanResult) { // Set的add方法返回true表示元素之前不存在,添加成功 if (existingResults.add(result)) { list.add(result) } } // 移除元素:同步更新Set和StateList fun removeScanResult(result: ScanResult) { if (existingResults.remove(result)) { list.remove(result) } }
关键注意点
- 必须重写
ScanResult的equals和hashCode:Set依赖这两个方法判断元素是否重复。如果ScanResult是数据类,Kotlin会自动基于所有属性生成这两个方法;如果是普通类,需手动实现(比如根据唯一标识字段如id):
class ScanResult(val id: String) { override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false other as ScanResult return id == other.id } override fun hashCode(): Int { return id.hashCode() } }
方案二:封装自定义的唯一StateList类
如果希望对外接口和普通mutableStateListOf完全一致,同时自动保证唯一性,可以封装一个实现MutableList接口的自定义类,内部同步维护SnapshotStateList和MutableSet:
import androidx.compose.runtime.snapshots.SnapshotStateList import androidx.compose.runtime.mutableStateListOf class UniqueStateList<T>( private val stateList: SnapshotStateList<T> = mutableStateListOf(), private val backingSet: MutableSet<T> = mutableSetOf() ) : MutableList<T> by stateList { // 重写add方法,仅添加不存在的元素 override fun add(element: T): Boolean { return if (backingSet.add(element)) { stateList.add(element) } else { false } } // 重写指定位置添加的方法 override fun add(index: Int, element: T) { if (backingSet.add(element)) { stateList.add(index, element) } } // 批量添加:仅加入不存在的元素 override fun addAll(elements: Collection<T>): Boolean { val newElements = elements.filterNot { backingSet.contains(it) } return if (newElements.isNotEmpty()) { backingSet.addAll(newElements) stateList.addAll(newElements) } else { false } } // 指定位置批量添加 override fun addAll(index: Int, elements: Collection<T>): Boolean { val newElements = elements.filterNot { backingSet.contains(it) } return if (newElements.isNotEmpty()) { backingSet.addAll(newElements) stateList.addAll(index, newElements) } else { false } } // 移除元素时同步更新Set override fun remove(element: T): Boolean { return if (backingSet.remove(element)) { stateList.remove(element) } else { false } } // 根据索引移除元素时同步更新Set override fun removeAt(index: Int): T { val removedElement = stateList.removeAt(index) backingSet.remove(removedElement) return removedElement } // 清空时同步清空两个集合 override fun clear() { backingSet.clear() stateList.clear() } // 批量移除元素时同步更新 override fun removeAll(elements: Collection<T>): Boolean { val removed = backingSet.removeAll(elements) return if (removed) { stateList.removeAll(elements) } else { false } } // 保留指定元素时同步更新 override fun retainAll(elements: Collection<T>): Boolean { val retained = backingSet.retainAll(elements) return if (retained) { stateList.retainAll(elements) } else { false } } }
使用方式
直接像普通mutableStateListOf一样初始化即可:
val list by lazy { UniqueStateList<ScanResult>() }
后续调用list.add()、list.remove()等方法时,会自动保证元素唯一性,同时Compose能正确感知列表变化触发重组。
内容的提问来源于stack exchange,提问作者Compose Learner
相关产品推荐
相关产品推荐

