You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin中Spinner组件selectedItem始终为null问题求助

问题排查: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:38:20