欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android Compose Column列表不自動(dòng)刷新問題

 更新時(shí)間:2023年01月30日 17:03:31   作者:氦客  
這篇文章主要介紹了Android Compose Column列表數(shù)據(jù)更新列表不刷新的問題,總的來說這并不是一道難題,那為什么要拿出這道題介紹?拿出這道題真正想要傳達(dá)的是解題的思路,以及不斷優(yōu)化探尋最優(yōu)解的過程。希望通過這道題能給你帶來一種解題優(yōu)化的思路

1. 背景

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

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

效果如下

但是如果是使用Column/Row/LazyColumn/LazyRow列表的時(shí)候,無論怎么更新數(shù)據(jù),界面都不會(huì)刷新

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()
        )
    }
}

可以看到,點(diǎn)擊了按鈕后,列表完全沒有刷新

這是為什么了 ?

2. 解決方案

當(dāng)時(shí)很不解,為啥其他類型都是可以的,使用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()
        )
    }
}

3. 原因

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

3.1 mutableStateOf為什么可以更新UI

我們以mutableStateOf()這個(gè)為例

var value by mutableStateOf(0)

首先,我們要明白,mutableStateOf()返回的是一個(gè)MutableState對(duì)象,MutableState中有一個(gè)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源碼,可以發(fā)現(xiàn),mutableStateOf()返回的是繼承自MutableStateSnapshotMutableState對(duì)象,路徑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)

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

  • 當(dāng)value被讀的時(shí)候,不光把值返回,還會(huì)記錄一下在哪被讀的
  • 當(dāng)value被寫的時(shí)候,不止把這個(gè)值給改了,還會(huì)去查找在哪里被讀過,然后通知這些被讀過的地方,通知UI進(jìn)行刷新

4. 結(jié)論

因?yàn)槲覀儾僮?code>String、Int等基礎(chǔ)類型的時(shí)候,都是通過getset()來獲取、設(shè)置數(shù)據(jù)的,所以這操作會(huì)被SnapshotMutableStateImpl記錄下來,而List、Map這種集合,我們是通過add、remove來更新數(shù)據(jù)的,所以不會(huì)觸發(fā)SnapshotMutableStateImpl value屬性的set

4.1 解決方案一

使用mutableStateListOf替代mutableStateOf,mutableStateListOf內(nèi)部對(duì)add、remove方法也進(jìn)行了重寫

4.2 解決方案二

新創(chuàng)建一個(gè)List,然后賦值給原來的list,這樣就會(huì)觸發(fā)set

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

5.自己實(shí)現(xiàn)一個(gè)mutableStateOf()

我們也可以自己來實(shí)現(xiàn)一個(gè)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")
    }
}

到此這篇關(guān)于Android Compose Column列表不自動(dòng)刷新問題的文章就介紹到這了,更多相關(guān)Android Compose Column內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論