中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Android?Compose?Column列表不自動刷新問題如何解決

發布時間:2023-02-01 09:56:12 來源:億速云 閱讀:238 作者:iii 欄目:開發技術

本篇內容介紹了“Android Compose Column列表不自動刷新問題如何解決”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

    1. 背景

    我們都知道,Compose可以使用mutableStateOf和UI進行綁定,改變值之后,就可以改變UI。

    var value by remember { mutableStateOf(0) }
    var imageVisible by remember { mutableStateOf(true) }
    Column {
        Text(text = "現在的值是:$value")
        Button(onClick = {
            value++ //修改值,自動改變UI
        }) {
            Text(text = "Add Value")
        }
        AnimatedVisibility(visible = imageVisible) {
            Image(
                painter = painterResource(id = R.mipmap.photot1),
                contentDescription = "",
                Modifier.width(260.dp)
            )
        }
        Button(onClick = {
            imageVisible = !imageVisible //修改值,自動顯示/隱藏UI
        }) {
            Text(text = "Show/Hide")
        }
    }

    效果如下

    Android?Compose?Column列表不自動刷新問題如何解決

    但是如果是使用Column/Row/LazyColumn/LazyRow列表的時候,無論怎么更新數據,界面都不會刷新

    val list = ArrayList<String>()
    for (i in 0..10) {
        list.add(i.toString())
    }
    var stateList by remember { mutableStateOf(list) }
    Button(onClick = {
        stateList.add("添加的值:${Random.nextInt()}")
    }, modifier = Modifier.fillMaxWidth()) {
        Text(text = "添加值")
    }
    Button(onClick = {
        stateList.removeAt(stateList.size - 1)
    }, modifier = Modifier.fillMaxWidth()) {
        Text(text = "刪除值")
    }
    LazyColumn {
        items(stateList.size) { index ->
            Text(
                text = "${stateList.get(index)}",
                textAlign = TextAlign.Center,
                modifier = Modifier
                    .height(24.dp)
                    .fillMaxWidth()
            )
        }
    }

    可以看到,點擊了按鈕后,列表完全沒有刷新

    Android?Compose?Column列表不自動刷新問題如何解決

    這是為什么了 ?

    2. 解決方案

    當時很不解,為啥其他類型都是可以的,使用List就不行了呢 ?

    查閱了好久,終于找到了解決方案

    mutableStateOf改用mutableStateListOf就可以了

    var stateList = remember { mutableStateListOf<String>() }
    for (i in 0..10) {
        stateList.add(i.toString())
    }
    Button(onClick = {
        stateList.add("添加的值:${Random.nextInt()}")
    }, modifier = Modifier.fillMaxWidth()) {
        Text(text = "添加值")
    }
    Button(onClick = {
        stateList.removeAt(stateList.size - 1)
    }, modifier = Modifier.fillMaxWidth()) {
        Text(text = "刪除值")
    }
    LazyColumn {
        items(stateList.size) { index ->
            Text(
                text = "${stateList.get(index)}",
                textAlign = TextAlign.Center,
                modifier = Modifier
                    .height(24.dp)
                    .fillMaxWidth()
            )
        }
    }

    Android?Compose?Column列表不自動刷新問題如何解決

    3. 原因

    解決方案很簡單,但是這是為什么呢 ?

    3.1 mutableStateOf為什么可以更新UI

    我們以mutableStateOf()這個為例

    var value by mutableStateOf(0)

    首先,我們要明白,mutableStateOf()返回的是一個MutableState對象,MutableState中有一個var value: T屬性

    interface MutableState<T> : State<T> {
        override var value: T
        operator fun component1(): T
        operator fun component2(): (T) -> Unit
    }
    interface State<out T> {
        val value: T
    }

    查看mutableStateOf源碼,可以發現,mutableStateOf()返回的是繼承自MutableStateSnapshotMutableState對象,路徑mutableStateOf()-> createSnapshotMutableState() -> ParcelableSnapshotMutableState-> SnapshotMutableStateImpl,可以看到有這樣一段代碼

    override var value: T
        get() = next.readable(this).value
        set(value) = next.withCurrent {
            if (!policy.equivalent(it.value, value)) {
                next.overwritable(this, it) { this.value = value }
            }
        }
    private var next: StateStateRecord<T> = StateStateRecord(value)

    這里就是重點,SnapshotMutableStateImplvalue屬性重寫了get()set()方法

    • value被讀的時候,不光把值返回,還會記錄一下在哪被讀的

    • value被寫的時候,不止把這個值給改了,還會去查找在哪里被讀過,然后通知這些被讀過的地方,通知UI進行刷新

    4. 結論

    因為我們操作StringInt等基礎類型的時候,都是通過getset()來獲取、設置數據的,所以這操作會被SnapshotMutableStateImpl記錄下來,而ListMap這種集合,我們是通過addremove來更新數據的,所以不會觸發SnapshotMutableStateImpl value屬性的set

    4.1 解決方案一

    使用mutableStateListOf替代mutableStateOfmutableStateListOf內部對addremove方法也進行了重寫

    4.2 解決方案二

    新創建一個List,然后賦值給原來的list,這樣就會觸發set

    var stateList by remember { mutableStateOf(list) }
    val tempList = ArrayList<String>()
    for (value in stateList) {
        tempList.add(value)
    }
    tempList.add("添加的值:${Random.nextInt()}")
    stateList = tempList //賦值的時候會觸發刷新UI

    5.自己實現一個mutableStateOf()

    我們也可以自己來實現一個mutableStateOf,偽代碼如下

    class Test {
        interface State<out T> {
            val value: T
        }
        interface MutableState<T> : State<T> {
            override var value: T
            /*operator fun component1(): T
            operator fun component2(): (T) -> Unit*/
        }
        inline operator fun <T> State<T>.getValue(thisObj: Any?, property: KProperty<*>): T = value
        inline operator fun <T> MutableState<T>.setValue(
            thisObj: Any?,
            property: KProperty<*>,
            value: T
        ) {
            this.value = value
        }
        interface SnapshotMutableState<T> : MutableState<T> {
            val policy: SnapshotMutationPolicy<T>
        }
        interface SnapshotMutationPolicy<T> {
            fun equivalent(a: T, b: T): Boolean
            fun merge(previous: T, current: T, applied: T): T? = null
        }
        internal open class SnapshotMutableStateImpl<T>(
            val _value: T,
            override val policy: SnapshotMutationPolicy<T>
        ) : /*StateObject, */SnapshotMutableState<T> {
            private var next : T = 52 as T
            @Suppress("UNCHECKED_CAST")
            override var value: T
                get() = next
                /*get() {
                    Log.i(TAGs.TAG, "getValue:$field")
                    return "" as T
                }*/
                set(value) {
                    Log.i(TAGs.TAG, "setValue")
                    this.value = value
                }
            /*override fun component1(): T {
                //TODO("Not yet implemented")
            }
            override fun component2(): (T) -> Unit {
                //TODO("Not yet implemented")
            }*/
        }
        internal class ParcelableSnapshotMutableState<T>(
            value: T,
            policy: SnapshotMutationPolicy<T>
        ) : SnapshotMutableStateImpl<T>(value, policy)/*, Parcelable*/ {
        }
        fun <T> mutableStateOf(
            value: T,
            policy: SnapshotMutationPolicy<T> = structuralEqualityPolicy()
        ): MutableState<T> = createSnapshotMutableState(value, policy)
        fun <T> structuralEqualityPolicy(): SnapshotMutationPolicy<T> =
            StructuralEqualityPolicy as SnapshotMutationPolicy<T>
        private object StructuralEqualityPolicy : SnapshotMutationPolicy<Any?> {
            override fun equivalent(a: Any?, b: Any?) = a == b
            override fun toString() = "StructuralEqualityPolicy"
        }
        fun <T> createSnapshotMutableState(
            value: T,
            policy: SnapshotMutationPolicy<T>
        ): SnapshotMutableState<T> = ParcelableSnapshotMutableState(value, policy)
        fun main() {
            var sizeUpdate by mutableStateOf(48)
            Log.i(TAGs.TAG, "sizeUpdate:$sizeUpdate")
            sizeUpdate = 64
            Log.i(TAGs.TAG, "sizeUpdate>>$sizeUpdate")
        }
    }

    “Android Compose Column列表不自動刷新問題如何解決”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    宝丰县| 昌吉市| 溧阳市| 隆安县| 毕节市| 壤塘县| 溧水县| 康平县| 西吉县| 内乡县| 和顺县| 桐柏县| 西藏| 肇州县| 正安县| 商都县| 商河县| 鹤山市| 宜宾市| 读书| 东丽区| 平乡县| 冀州市| 连南| 麻阳| 名山县| 龙山县| 老河口市| 中山市| 沅陵县| 松原市| 延长县| 江门市| 赤城县| 长垣县| 凤山市| 佛冈县| 乌恰县| 洞口县| 马龙县| 康平县|