android - 在 ListView 中添加到 ArrayList 时出现 ArrayIndexOutOfBoundsException
问题描述
我发现了有关此异常的其他几个问题,但没有一个问题适合我。
这是我的整个代码:
class MainActivity : AppCompatActivity() {
private lateinit var listView: ListView
private lateinit var addItem: ImageButton
private lateinit var adapter: MyAdapter
private val names = arrayListOf("Person 1", "Person 2", "Person 3", "Person 4", "Person 5",
"Person 6", "Person 7", "Person 8", "Person 9", "Person 10")
private val descriptions = arrayListOf("Actor", "Activist", "Athlete", "Scientist", "Astronaut",
"Engineer", "Software Developer", "Politician", "Soldier", "Shopkeeper")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
listView = list_view as ListView
addItem = addButton as ImageButton
adapter = MyAdapter(this, names, descriptions)
listView.adapter = adapter
addItem.setOnClickListener {
names.add("Person 11")
descriptions.add("Mortician")
adapter.notifyDataSetChanged()
Toast.makeText(this, "Button Clicked", Toast.LENGTH_LONG).show()
}
}
}
private class MyAdapter(val context: Context, val names: ArrayList<String>,
val descriptions: ArrayList<String>) : BaseAdapter() {
override fun getCount(): Int {
return names.size
}
override fun getViewTypeCount(): Int {
return count
}
override fun getItemViewType(position: Int): Int {
return position
}
override fun getItem(position: Int): Any {
return position
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
val viewHolder: ViewHolder?
return if (convertView == null) {
val convertViewMutable = LayoutInflater.from(context).inflate(R.layout.activity_custom, parent, false)
val checkBox: CheckBox = convertViewMutable.findViewById(R.id.checkBox_name) as CheckBox
val desc: TextView = convertViewMutable.findViewById(R.id.textView_desc) as TextView
viewHolder = ViewHolder(checkBox, desc)
convertViewMutable.tag = viewHolder
checkBox.text = names[position]
desc.text = descriptions[position]
convertViewMutable
} else
convertView
}
}
private data class ViewHolder(private val checkBox: CheckBox, private val textView: TextView)
当我运行程序时,列表看起来很好。当我单击按钮添加新名称和描述时,它会运行侦听器中的所有代码,因为我看到 Toast 出现了。然后我可以向下滚动并在列表底部查看新项目。但是,当我向上滚动时,会抛出错误。
我看到有人说你不应该覆盖 getViewTypeCount() 和 getItemViewType() 的答案,但我只是覆盖它们,因为如果我把它们拿出来,当我滚动浏览它们时,我的列表中的项目会重复。还有答案说发生错误是因为 getItemViewType() 返回的数字大于 getViewTypeCount() 但他们没有提到如何修复它。
解决方案
发生这种情况是因为您使用 ViewHolder 不当。
但在我解释问题之前,我想告诉你你重写getViewTypeCount()和getItemViewType()的方式是一个严重的错误。
ViewHolder 的意义在于它可以保留一个视图以供 ListView 重用。这样,ListView 就不必为 ArrayList 中的每一项都重新创建一个新视图。
但是,您的代码完全相反。通过您如何覆盖getViewTypeCount()和getItemViewType(),您实际上是在破坏 ViewHolders 的目的。您告诉 ListView 为 ArrayList 中的每个项目创建一个新的 ViewHolder,这使得它无法重用存储在 ViewHolder 中的视图。
不覆盖这两种方法会导致项目重复的原因与您问题的解决方案有关,即正确使用ViewHolder。
要正确使用 ViewHolder,当您看到以下代码时:
} else
convertView
不要只返回 convertView。从 convertView 的 TAG 中获取 ViewHolder,并使用当前项目的数据更新 CheckBox 和 TextView。
这样,您的 ViewHolder 将始终保存它所要保存的名称和描述。
您还将正确地重用 ViewHolder,而不是为每个项目创建一个新的。
您之前的代码在滚动时复制项目的原因是因为您没有使用正确的数据更新 ViewHolder,所以它只是使用了之前项目中的旧数据。
所以总结一下:
不要覆盖getViewTypeCount()和getItemViewType()
让您的getView()方法使用正确的数据更新 ViewHolder 的视图。
推荐阅读
- git - 什么是 git status 替代品!svn状态结果
- json - 如何根据上述jq数组中对象中的元素值选择/获取对象元素的(对象数组)键?
- nginx - 向上游发送请求时,nginx 失败(32:管道损坏),
- python - 使用子列表进行列表理解
- opencv - 找到我们从远处在图像上看到的颜色
- python - 在 python 中切片的这种行为是什么?
- python - 如何根据 groupby 操作生成的组获取 pandas DataFrame 的组 ID 值列
- loops - 这个嵌套的while循环要运行多少次?
- python - 如何使用 python base64 代码 url 解码?
- java - 使用 InternetAddress.validate() 检查电子邮件地址