Android 8.0中使用Kotlin创建的ArrayList数据源Spinner无法触发OnItemSelected事件及更新问题
Spinner绑定ArrayList数据源后无法触发OnItemSelected及更新显示的解决方案
问题场景
我在用Kotlin开发Android 8.0应用时碰到了Spinner的异常问题:
- 一个通过资源字符串数组创建的Spinner工作完全正常;
- 另一个以
ArrayList作为数据源的Spinner,点击列表项时完全无法触发OnItemSelected回调,也不能更新自身的显示状态。
以下是我最初的错误实现代码:
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val modules = ArrayList<Module>() val bufferedReader = BufferedReader(InputStreamReader(resources.openRawResource(R.raw.mod_code))) var line = bufferedReader.readLine() while(line != null) { val values = line.split(",") modules.add(Module(values[0].replace("", "").toInt(), values[1], values[2].replace("", "").toDouble())) line = bufferedReader.readLine() } val moduleCodeArray = ArrayList<String>() val yearSpinner: Spinner = findViewById(R.id.year) yearSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener{ override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { val item = parent?.getItemAtPosition(position).toString() Toast.makeText(parent?.context, "Selected: $item", Toast.LENGTH_LONG).show() moduleCodeArray.clear() for(module in modules) { if(module.year == position + 1) { moduleCodeArray.add(module.moduleCode) } } } override fun onNothingSelected(parent: AdapterView<*>?) { } } ArrayAdapter.createFromResource( this, R.array.years, R.layout.custom_spinner ).also { adapter -> adapter.setDropDownViewResource(R.layout.custom_spinner_dropdown) yearSpinner.adapter = adapter } println(moduleCodeArray) val moduleCodeSpinner = findViewById<Spinner>(R.id.module_code) moduleCodeSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { val item = parent?.getItemAtPosition(position).toString() Toast.makeText(parent?.context, "Selected: $item", Toast.LENGTH_LONG).show() } override fun onNothingSelected(parent: AdapterView<*>?) {} } ArrayAdapter( this, R.layout.custom_spinner, moduleCodeArray ).also { adapter -> adapter.setDropDownViewResource(R.layout.custom_spinner_dropdown) moduleCodeSpinner.adapter = adapter } } }
问题根源
核心问题在于数据更新与适配器绑定的时机不匹配:moduleCodeArray是在yearSpinner的OnItemSelected回调中才被填充数据的,但我最初在onCreate方法里就一次性创建了适配器并绑定到moduleCodeSpinner。此时moduleCodeArray是空的,后续回调中更新数组内容后,旧的适配器完全感知不到数据变化,也没有重新绑定新的数据源,最终导致Spinner既无法更新显示,也无法响应选中事件。
解决思路
把ArrayAdapter的创建与绑定逻辑,移到yearSpinner的OnItemSelected回调内部。这样每次选中年份后,都会基于更新后的moduleCodeArray创建新的适配器并绑定到moduleCodeSpinner,确保Spinner能获取到最新的数据源,同时正常响应选中事件。
修正后的正确代码
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val modules = ArrayList<Module>() val bufferedReader = BufferedReader(InputStreamReader(resources.openRawResource(R.raw.mod_code))) var line = bufferedReader.readLine() while(line != null) { val values = line.split(",") modules.add(Module(values[0].replace("", "").toInt(), values[1], values[2].replace("", "").toDouble())) line = bufferedReader.readLine() } val moduleCodeArray = ArrayList<String>() val moduleCodeSpinner = findViewById<Spinner>(R.id.module_code) val yearSpinner: Spinner = findViewById(R.id.year) yearSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener{ override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { val item = parent?.getItemAtPosition(position).toString() Toast.makeText(parent?.context, "Selected: $item", Toast.LENGTH_LONG).show() moduleCodeArray.clear() for(module in modules) { if(module.year == position + 1) { moduleCodeArray.add(module.moduleCode) } } // 将适配器的创建与绑定移到这里,确保每次数据更新后都重新绑定 ArrayAdapter( applicationContext, R.layout.custom_spinner, moduleCodeArray ).also { adapter -> adapter.setDropDownViewResource(R.layout.custom_spinner_dropdown) moduleCodeSpinner.adapter = adapter } } override fun onNothingSelected(parent: AdapterView<*>?) { } } ArrayAdapter.createFromResource( this, R.array.years, R.layout.custom_spinner ).also { adapter -> adapter.setDropDownViewResource(R.layout.custom_spinner_dropdown) yearSpinner.adapter = adapter } moduleCodeSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { val item = parent?.getItemAtPosition(position).toString() Toast.makeText(parent?.context, "Selected: $item", Toast.LENGTH_LONG).show() } override fun onNothingSelected(parent: AdapterView<*>?) {} } } }
内容的提问来源于stack exchange,提问作者mug1wara26
相关产品推荐
相关产品推荐

