Kotlin中Spinner组件selectedItem始终为null问题求助
我仔细看了你的CurrencyFragment代码,发现几个关键问题导致Spinner的selectedItem始终为null,下面逐一分析并给出修复方案:
1. 数据加载完成前就通知Adapter更新,选中时机错误
你在populateSpinnerAdapter方法中,调用currencyViewModel.loadCurrencyList()获取异步数据后,立刻就调用了currenciesAdapter.notifyDataSetChanged(),但这时候ViewModel的异步请求还没完成,Observer还没收到数据,currencies列表还是空的。同时你在initSpinners里提前调用setSelection(0),但此时Spinner没有任何数据,这个选中操作根本不会生效。
修复方案:
把notifyDataSetChanged()和setSelection()移到Observer内部,确保只有当数据真正加载完成后,才通知Adapter更新并设置选中项:
private fun populateSpinnerAdapter() { this.currencyViewModel.loadCurrencyList() ?.observe(this, Observer { currencyList -> currencyList?.let { // 先清空旧数据,避免重复添加 currencies.clear() it.forEach { currency -> currencies.add("${currency.code} ${currency.country}") } // 数据更新后通知Adapter currenciesAdapter.notifyDataSetChanged() // 数据就绪后再设置默认选中第0项 sp_from_country.setSelection(0) sp_to_country.setSelection(0) } }) this.currenciesAdapter.setDropDownViewResource(R.layout.item_spinner) }
2. 重复添加数据导致的潜在问题
每次Observer收到currencyList时,你直接往currencies列表里追加数据,如果ViewModel多次发射数据(比如配置变更后重新加载),会导致列表里出现重复项,也可能影响Spinner的选中状态。
修复方案:
在添加新数据前先调用currencies.clear(),确保每次都是全新的数据集合(已经包含在上面的修复代码中)。
3. Spinner初始化时无数据,提前设置选中无效
在initSpinners中,你用空的currencies列表初始化ArrayAdapter,然后立刻设置setSelection(0),但此时Spinner没有任何选项,这个操作不会有任何效果。
修复方案:
移除initSpinners中的setSelection(0)调用,等待Observer中数据加载完成后再设置默认选中,就像上面修复方案里那样。
额外的空安全优化
在convert方法中,建议先判断selectedItem是否为null,避免空指针异常:
private fun convert() { val quantity = edt_value.text.toString() // 先检查选中项是否存在 val fromSelectedItem = sp_from_country.selectedItem ?: run { Log.d("Currency Fragment", "请选择源货币") return } val toSelectedItem = sp_to_country.selectedItem ?: run { Log.d("Currency Fragment", "请选择目标货币") return } this.currencyForm = getCurrencyCode(fromSelectedItem.toString()) this.currencyTo = getCurrencyCode(toSelectedItem.toString()) val currencies = "$currencyForm,$currencyTo" if (quantity.isNotEmpty() && currencyForm != currencyTo) { this.currencyViewModel.getAvailableExchange(currencies) ?.observe(this, Observer { availableExchange -> availableExchange?.run { exchange(quantity.toDouble(), availableExchangeMap) } }) } }
最后,你可以在Observer里加个Log打印,确认currencyViewModel.loadCurrencyList()是否真的能获取到数据:
currencyList?.let { Log.d("Currency Fragment", "加载到${it.size}条货币数据") // ... 剩下的逻辑 }
内容的提问来源于stack exchange,提问作者An Quoc Duy Nguyen

