本文介绍: 对于 String、Int 这些类型,Compose 提供了 mutableStateOf,难道对于 List 这种这么常用的类型,就没有一个 mutable*** 的函数我们用?

Jekpack Compose状态订阅&自动刷新系列

     【 聊聊 Jetpack Compose 的 “状态订阅&自动刷新” – – MutableState/mutableStateOf

     【 聊聊 Jetpack Compose 的 “状态订阅&自动刷新” – – remember 和重组作用域

     【 聊聊 Jetpack Compose 的 “状态订阅&自动刷新” – – 有状态、无状态状态提升?】

     【 聊聊 Jetpack Compose 的 “状态订阅&自动刷新” – – mutableStateListOf

     【 聊聊 Jetpack Compose 的 “状态订阅&自动刷新” – – 你真的了解重组吗?】


讲任何一个新的主题或者知识点,习惯性的从 Demo 开始,比如

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        var name by mutableStateOf("Hi, Compose")

        setContent {
            Text(name)
        }
    }
}

这段代码已经熟的不能再熟了,如果我们by mutableStateOf 初始化一个变量,那 name 就会变成一个被 Compose 自动订阅变量

我们前面所有的例子,都是用 by mutableStateOf 包了一个 String,如果换成别的类型,行不行?肯定可以,不用想。

fun <T> mutableStateOf(
    value: T,  // 泛型参数
    policy: SnapshotMutationPolicy<T> = structuralEqualityPolicy()
): MutableState<T> = createSnapshotMutableState(value, policy)

比如 Int 类型:

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        var num by mutableStateOf(1)

        setContent {
            Text(
                text = "当前数值$num",
                Modifier.clickable {
                    num++
                }
            )
        }
    }
}

代码不做解释了,直接效果

在这里插入图片描述

比如:List 类型

// num 类型:MutableList<Int>
// mutableStateOf 类型:MutableState<MutableList<Int>>
var nums by mutableStateOf(mutableListOf(1, 2, 3))

我们代码里面用起来:

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        var nums by mutableStateOf(mutableListOf(1, 2, 3))

        setContent {
            Column {
                for (num in nums) {
                    Text("第 $num文字")
                }
            }
        }
    }
}

运行

在这里插入图片描述

现在我们稍微改下代码

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        var nums by mutableStateOf(mutableListOf(1, 2, 3))

        setContent {
            Column {
                Button(onClick = {
                    nums.add(nums.last() + 1)
                }) {
                    Text("List 加 1")
                }
                for (num in nums) {
                    Text("第 $num文字")
                }
            }
        }
    }
}

代码简单我们添加了一个 Button,每次点击后,nums添加一个值,比最有一个值大 1。

运行

在这里插入图片描述

???没生效啊!为什么

我们先来考虑一个问题,mutableStateOf 原理什么?前面的问题我们说过,可以回忆一下:

mutableStateOf 之所以可以变量进行订阅和刷新,主要是因为内部get() 和 set() 方法加了钩子,或者说它的 set() 方法赋值!是改变了变量指向,它是直接对象替换了,但在我们这个代码里面 nums 仅仅是改变了它内部的状态:

在这里插入图片描述

对这块如果有点懵,可以看【 聊聊 Jetpack Compose 的 “状态订阅&amp;自动刷新” – – MutableState/mutableStateOf 】篇文章

所以,它不会出发 setValue() 的调用,所以不会出发自动刷新的操作

在这里插入图片描述

为了验证是不是因为没有重组,我们可以验证下:

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        var nums by mutableStateOf(mutableListOf(1, 2, 3))
        var refresh by mutableStateOf("强制刷新")

        setContent {
            Column {
                Text(refresh, Modifier.clickable { refresh = "刷新完成"})
                Button(onClick = {
                    nums.add(nums.last() + 1)
                }) {
                    Text("List 加 1")
                }
                for (num in nums) {
                    Text("第 $num 块文字")
                }
            }
        }
    }
}

我们添加了一个 Text() 组件,改变 refresh 的值,那么理论上它就会带着整个重组作用域内的组件全部刷新,包括 List。

运行

在这里插入图片描述

成功刷新 List!

现在我们就很清楚了,mutableStateOf 没法对 List 类型的对象没法实现类似 String、Int 的自动订阅及刷新,那有没有解决办法

上面我们说过了,问题的根本原因是 List 只是内部的变化,而不是它自己本身对象的变化,那我们直接内部操作完后直接把 List 重新给换了不就行了,试试:

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        var nums by mutableStateOf(mutableListOf(1, 2, 3))

        setContent {
            Column {
                Button(onClick = {
                    // nums 重新赋值
                    nums = nums.toMutableList().apply {
                        add(nums.last() + 1)
                    }
                }) {
                    Text("List 加 1")
                }
                for (num in nums) {
                    Text("第 $num 块文字")
                }
            }
        }
    }
}

运行

在这里插入图片描述

但这样写就会显得很奇怪,我是明白原理了,我这样也是可以实现正常的刷新,但不太对劲:既然对于 String、Int 这些类型,Compose 提供了 mutableStateOf,难道对于 List 这种这么常用的类型,就没有一个 mutable*** 的函数给我们用?

有,它就是 mutableStateListOf!它可以观测到内部 List 的数据变化!

我们可以像下面这样申明:

var nums by mutableStateListOf(mutableListOf(1, 2, 3))  // 有红线标注写法错误

// mutableStateListOf 是内部元素被观测,而不是它本身被观测,所以我们要把 `by` 换成 `=`
var nums = mutableStateListOf(mutableListOf(1, 2, 3))

// `var` 也可以换成 `val`
val nums = mutableStateListOf(mutableListOf(1, 2, 3))

// mutableStateListOf 本身就代表一个可观测的 List,所以 mutableListOf 也可以去除
val nums = mutableStateListOf(1, 2, 3)  // 这就是最终的写法

这个时候我们就可以优化代码了:

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val nums = mutableStateListOf(1, 2, 3)

        setContent {
            Column {
                Button(onClick = {
                    nums.add(nums.last() + 1)
                }) {
                    Text("List 加 1")
                }
                for (num in nums) {
                    Text("第 $num 块文字")
                }
            }
        }
    }
}

运行

在这里插入图片描述

提到 List,我们就会想到 Map,同样 Map 也提供了一个 mutableStateMapOf!它也可以观测到内部 Map 的数据变化!

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val maps = mutableStateMapOf(1 to "One", 2 to "Two")
        setContent {
            Column {
                Button(onClick = {
                    maps[3] = "Three"
                }) {
                    Text("Maps 加 1")
                }
                for ((key, value) in maps) {
                    Text("$key 对应 value: $value")
                }
            }
        }
    }
}

运行

在这里插入图片描述

原文地址:https://blog.csdn.net/pepsimaxin/article/details/134789712

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_43432.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注