持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第3天,点击查看活动详情
为了活动小家电,接着上篇搞!
方案三
创建和管理一个状态数据类
ViewModel
@HiltViewModel
class ProgramThreeViewModel @Inject constructor(
private val repository: LibraryRepository
) : ViewModel() {
data class State(
val loading: Boolean = true,
val error: Boolean = false,
val name: String = "",
val price: String = ""
)
private val _state: MutableStateFlow<State> = MutableStateFlow(State())
val state: StateFlow<State> = _state.asStateFlow()
init {
viewModelScope.launch {
val response = repository.getBookInfo()
_state.update { state -> state.copy(loading = true) }
response
.onSuccess { bookInfo ->
_state.update { state ->
state.copy(
loading = false,
name = bookInfo.name,
price = bookInfo.price
)
}
}
.onFailure {
_state.update { state ->
state.copy(
loading = false,
error = true
)
}
}
}
}
}
Activity
@AndroidEntryPoint
class ProgramThreeActivity : BindActivity() {
private val viewModel: ProgramThreeViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lifecycleScope.launch {
viewModel.state.collect { state ->
// 加载中展示
binding.ivLoading.isVisible = state.loading
// 加载异常展示
binding.ivError.isVisible = state.error
// 书名展示
binding.tvName.text = state.name
// 价格展示
binding.tvPrice.text = state.price
}
}
}
}
优点
- 所有必要的状态都可以包含在一个数据中,只需要调整数据值即可,因此可以方便地处理 UI 的业务逻辑。
- 通过使用数据类,提供了一种强大的局部更新方法,数据类的
copy
方法。 - 改变 UI 的代码没有分散相对比较集中,都是统一返回的,所以代码分析很方便。
- 结合LiveData或StateFlow的功能和distinctUntilChanged(根据条件,如果生产的值和上个发送的值相同,值就会被过滤掉),可以应用到想要的形式的数据绑定
缺点
- 虽然
copy
保证了一定程度的安全性,但它很容易受到数据更改的并发问题的影响。 - 当屏幕变得更复杂时,数据类所需的属性急剧增加。
- 数据类 即使特征值发生变化,也需要注意动画
使用场景
- 如果对 UI 的小修改频繁发生
- 如果你的 UI 业务逻辑比较复杂
- 当频繁使用状态组合时
- 如果加载或错误也可以包含在状态中并进行处理