项目介绍
- Github: Orbit-mvi
- 官网: Orbit Multiplatform
示例程序
- 预览
- 添加依赖项到
build.gradle
scss
implementation("org.orbit-mvi:orbit-core:9.0.0")
implementation("org.orbit-mvi:orbit-viewmodel:9.0.0")
代码结构
- 为页面创建一个状态类
XXState
,包含所有状态信息,注意state
中的字段是val
的,不可变的,每次页面刷新都是发出一个新的state
对象
kotlin
data class MyState(
val isLike: Boolean = false, // 是否点赞
val likeCount: Int = 0, // 点赞数
)
- 为页面创建一个副作用类
XXEffect
,一些一次性事件,类如Toast, Loading都放在这里
kotlin
sealed class MyEffect {
data class Loading(val show: Boolean, val text: String? = null) : MyEffect()
data class Toast(val text: String) : MyEffect()
}
- 为页面创建ViewModel, 实现
ContainerHost
接口
kotlin
class MyViewModel : ViewModel(), ContainerHost<MyState, MyEffect> {
override val container = container<MyState, MyEffect>(MyState(likeCount = 232))
fun like() = intent {
if (state.isLike) {
postSideEffect(MyEffect.Toast("已点赞,不可重复点赞")) // 发送toast事件
return@intent
}
postSideEffect(MyEffect.Loading(show = true, text = "请稍候...")) // 发送loading
delay(500) // 模拟网络请求
reduce {
// 在此处生成新的state对象, 以便UI观察这个新state而改变
state.copy(isLike = true, likeCount = state.likeCount + 1)
}
postSideEffect(MyEffect.Loading(show = false)) // 关闭loading
postSideEffect(MyEffect.Toast("点赞成功"))
}
}
- 实现页面逻辑, 此处为
Activity
kotlin
// 监听state变化和sideEffect事件
viewModel.observe(this, state = ::render, sideEffect = ::handleEffect)
// 点击事件,此处无需过度封装为一个Intent, 直接调viewmodel函数就行
binding.tvLike.setOnClickListener {
viewModel.like()
}
// 渲染UI
fun render(state: MyState) {
...
binding.textView.text = state.likeCount.toString() // 更新点赞数
}
// 处理副作用
fun handleEffect(effect: MyEffect) {
when (effect) {
is MyEffect.Toast -> {
Toast.makeText(this, effect.text, Toast.LENGTH_SHORT).show()
}
}
}
总结
- 可以看到, 框架已经帮我们封装好了Kotlin协程和Flow的实现,我们只需要在viewModel中使用
intent{}
即可, 并且侵入性较小,只需要viewModel实现一个接口就行 - 对于副作用,例如Toast,使用
postSideEffect()
发出新的Effect对象 - 对于页面刷新,例如变更点赞数,使用
reduce{}
,将state.copy()
出一个新的对象并发出 - 本实例程序源码: Github