android - 在 Android 中制作有状态组件
问题描述
我在我的应用程序中使用 MVVM。当您输入查询并单击搜索按钮时,链如下:Fragment -> ViewModel -> Repository -> API -> Client。客户端是发出 HTTP 请求的地方。但是这里有一件事,客户端需要在初始化时进行调用并从服务器获取密钥。因此,为了防止在第一次调用完成之前进行任何调用,我需要能够从 Fragment 观察它,以便我可以禁用搜索按钮。由于链中的每个组件都可以与相邻的组件通信,因此所有组件都应该有一个状态。
我正在考虑实现一个StatefulComponent
类并制作所有组件来扩展它:
open class StatefulComponent protected constructor() {
enum class State {
CREATED, LOADING, LOADED, FAILED
}
private val currentState = MutableLiveData(State.CREATED)
fun setState(newState: State) {
currentState.value = newState
}
val state: LiveData<State> = currentState
val isLoaded: Boolean = currentState.value == State.LOADED
val isFailed: Boolean = currentState.value == State.FAILED
val isCompleted: Boolean = isLoaded || isFailed
}
这个想法是每个组件观察下一个并相应地更新自己。然而,这对 ViewModel 来说是不可能的,因为它已经在扩展ViewModel
超类。
我该如何解决这个问题?
解决方案
最常见的方法是使用密封类作为您的状态,因此您可以根据需要在每个状态案例中使用任何参数。
sealed class MyState {
object Loading : MyState()
data class Loaded(data: Data) : MyState()
data class Failed(message: String) : MyState()
}
在您的视图模型上,您将只有 1 个实时数据
class MyViewModel : ViewModel() {
private val _state = MutableLiveData<MyState>()
val state: LiveData<MyState> = _state
fun load() {
_state.postCall(Loading)
repo.loadSomeData(onData = { data ->
_state.postCall(Loaded(data))
}, onError = { error -> _state.postCall(Failed(error.message)) })
}
// coroutines approach
suspend fun loadSuspend() {
_state.postCall(Loading)
try {
_state.postCall(Loaded(repo.loadSomeDataSupend()))
} catch(e: Exception) {
_state.postCall(Failed(e.message))
}
}
}
而在片段上,只需观察状态
class MyFragment : Fragment() {
...
onViewCreated() {
viewModel.state.observer(Observer {
when (state) {
// auto casts to each state
Loading -> { button.isEnabled = false }
is Loaded -> { ... }
is Failed -> { ... }
}
}
)
}
}
推荐阅读
- python - 我无法从本地机器上生成的 url 访问我的烧瓶应用程序
- solr - 如何在 Solr 中使用 Config API 添加具有多个字典的建议器组件?
- java - SpringBoot Bean Validation 注解
- r - 使用for循环从r中的数据框中删除特定列
- javascript - JavaScript 键按住并释放
- xml - 使用 RMLMapper 将 XML 嵌套到 Turtle 映射
- laravel - Bootstrap 4在关闭时破坏模态
- r - 每次一行包含字符串中的字符时,如何添加一个计数器?
- open-liberty - MicroProfile REST客户端上的容错@Asynchronous导致Windows上打开自由核心转储
- javascript - 无法在 Javascript 中显示数据