Kotlin中let函数是否复制数据?其参数能否感知LiveData并发更新
问题解答
直接针对两个问题给出明确结论和原理:
关于letList和liveList的引用关联
letList能不能感知后续更新,完全取决于你更新liveList的写法:
- 符合
LiveData使用规范的写法:每次新增数据时创建新的列表实例(比如先把现有列表转成可变列表、加元素后,再通过setValue/postValue把新列表设置给LiveData)。这种情况下letList完全感知不到后续更新,它持有的只是let执行瞬间liveList.value指向的旧列表引用,和后续LiveData里存的新列表没有任何关系。 - 错误写法:直接拿到
LiveData内部存的可变列表调用add/remove修改,不重新调用setValue/postValue触发更新。这种情况下letList和LiveData内部持有的是同一个列表对象,确实能看到新增元素,但这种写法会导致LiveData的观察者根本收不到数据更新通知,属于典型的误用,完全不推荐。
关于是否是拷贝、循环是否会终止
- 首先明确:Kotlin的
let是内联函数,不会对传入的对象做任何拷贝,letList就是let执行那一刻viewModel.liveList.value返回的对象引用本身,既不是深拷贝也不是浅拷贝。 - 你写的这段轮询代码,只要
let执行时列表长度不足10,基本一定会死循环:
只要你是按规范更新LiveData(每次替换新列表实例),letList指向的旧列表永远不会被新增元素,它的size会一直停留在let执行时的数值,不管delay多久都到不了10,while会无限执行。
就算你用了上面说的错误写法(直接修改内部可变列表不换引用),由于代码跑在非主线程,还存在Java内存模型的线程可见性问题,循环线程不一定能及时看到其他线程对列表的修改,还是有概率卡死。
正确实现方案
别用轮询的方式等数据,完全违背LiveData的设计初衷:
- 如果是协程环境,直接用Flow监听,等列表满足条件再继续后续逻辑:
// 挂起等待,直到列表长度>=10时拿到最新列表继续执行 val validList = viewModel.liveList.asFlow().first { it.size >= 10 }
- 如果不用协程,就给
liveList注册正式的Observer,在回调里判断列表长度,满足条件后执行对应逻辑再移除观察者即可。
额外注意:
LiveData的value字段本身没有做线程同步,非主线程直接访问本身就可能拿到非最新值,不建议在非主线程轮询访问value。
内容的提问来源于stack exchange,提问作者user1785730
相关产品推荐
相关产品推荐

