假设我有一个带有以下项目的微调器:“ A”,“ B”,“ C”。如果用户尚未选择任何内容,则微调器将显示“未知”。
STEP ONE,用户过去可能已经选择了一个项目。因此,我在视图模型中加载数据,然后hasSelectedSomething
在视图模型中观察到LiveData
(对BE的异步调用,它将更新LiveData
):
viewModel.itemLiveData.observe(
viewLifecycleOwner,
Observer { item ->
hasSelectedSomething = (item != "unknown")
}
)
STEP TWO现在,我设置了微调器。如果用户尚未选择任何选项,我希望在“未知”项目中选择微调框,否则,我希望在用户之前选择的任何位置选择它。
if(!hasSelectedSomething) {
spinner.setSelection(itemAdapter.getPosition("unknown"))
} else {
spinner.setSelection(itemAdapter.getPosition(viewModel.getItemString()))
}
第三步我实现了spinner.onItemSelectedListener
:
spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>?, view: View?, pos: Int, id: Long) {
val selectedItem = spinner.getItemAtPosition(pos) as String
viewModel.updateItemWithSelection(selectedItem)
}
override fun onNothingSelected(parent: AdapterView<*>?) {}
}
我的问题是LiveData
的默认值为“ unknown”,这意味着微调器应从“ unknown”开始。然后,假设用户过去选择了“ B”,因此我以编程方式将微调器设置为“ B”。问题是.setSelection
触发onItemSelected
,将pos
设置为任意选择,此时pos
对应于“未知”。因此,发生的情况是LiveData
从“未知”(默认值)变为“ B”(从调用到BE的结果)到“未知”(onItemSelected选择了“未知”,因此它将该值传递给视图模型)。
我该如何解决这个问题?如何正确设置微调器,使其处理默认值,用户选择和以前的选择?
通常,如果onItemSelected的回调中包含逻辑,并且需要以编程方式设置项目,则通常的做法是:
(伪代码)
yourCallback = object: AdapterView.OnItemSelectedListener {
...
}
spinner.setOnItemSelected(null)
spinner.setValue(...)
spinner.setOnItemSelected(yourCallback)
因此,在强制微调器设置值之前,请始终删除回调。
“未知”应该是您的选择中的一项。 Spinner(afaicr)不支持“ null”(自2016年以来,我不得不最后一次使用它,它可能已更改),但ViewModel会吐一个值。
最后,不要在用户界面(if(!hasSelectedSomething) {
)中仅使viewModel吐出一个值(未知有效值),而让微调器简单地设置其值。 (记住要删除回调,设置值,再次设置回调以防止再次调用)。
您有一个ViewModel是有原因的,让UI通过观察微调器的值来简单地对状态变化做出反应。