这样写还是要出事,当进入社区时,会根据用户身份展示不同样式的发帖按钮。但在发帖的逻辑中是通过新建 PostState 实例来更新状态的,这样就会丢失原有按钮样式,所以得由上次状态生成新状态:
class CommunityViewModel : ViewModel() {
private val _postStateLiveData = MutableLiveData<PostState>()
val postStateLiveData: LiveData<PostState> = _postStateLiveData
fun post(){
// 获取当前状态
val currentState = _postStateLiveData.value
// 更改当前状态值
_postStateLiveData.value = currentState.apply {
clickable = false,
loading = true,
text = "发送中..."
}
viewModelScope.launch(Dispatchers.IO) {
// 获取当前状态并修改之
val currentState = _postStateLiveData.value
val response = api.post()
if(response.isFailed){
_postStateLiveData.postValue(currentState.apply { poorNetwork = true })
} else {
when(response.code) {
CODE_BAD_WORD -> _postStateLiveData.postValue(
currentState.apply { badWord = "敏感词" }
)
else -> _postStateLiveData.postValue(
currentState.apply {success = true }
)
}
}
}
}
}
复制代码
这样写接着出事。。。
现在_postStateLiveData.value
成了“共享变量”,会存在多线程并发读写,存在线程安全问题。
解决办法是COW
,即 copy on write,在写变量的时候先拷贝源变量,然后对副本写。
关于 COW 的详细分析可以点击面试题 | 有用过并发容器吗?有!比如网络请求埋点
为了禁止变量的直接写操作,遂把唯一数据源的所有字段都定义成 val:
data class PostState(
val clickable: Boolean = true,
val backgroundColor: Int = 0xFF00FF,
val text: String = "发帖",
val loading: Boolean = false,
val poorNetwork: Boolean = "",
val badWord: String = "",
val success: Boolean = false
)
作者:唐子玄
链接:https://juejin.cn/post/7087717477246369805
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。