ExpandableListAdapter 显示错误的 childViews
ExpandableListAdapter shows wrong childViews
我正在编写一个应用程序来显示药物组、药物及其信息的树视图。本质上,它是药物组的 ExpandableListView,它显示单个药物名称作为 children 视图,并在点击时打开一个包含更多信息的新片段。
我无法用正确的数据填充 child 视图。适配器似乎正确地获取了组数据,并且从日志记录和调试看来 child 数据似乎也被正确传递。但是,ExpandableListView 中 childViews 中的文本仅对我打开的第一组是正确的,接下来的每一组都显示看似随机的内容(打开顺序无关紧要)。 child观看次数正确。详细视图 (onClick) 显示正确的信息,按下后退按钮时,菜单将显示正确的信息(但是,任何新打开的组仍然显示错误的内容)。
我至少进行了 20 轮检查和澄清任何可疑代码,但无济于事。
澄清截图:
list view with two groups expanded
detail view, showing correct info (but not matching that shown in list view)
list view upon returning (notice contents now shown correctly)
这是 ExpandableListAdapter:
class MedicationsListAdapter(
private val context: Context,
private val groupList: List<String>,
private val itemList: List<List<String>>
) : BaseExpandableListAdapter() {
override fun getGroupCount(): Int {
return groupList.size
}
override fun getChildrenCount(groupPosition: Int): Int {
return itemList[groupPosition].size
}
override fun getGroup(groupPosition: Int): List<String> {
return itemList[groupPosition]
}
override fun getChild(groupPosition: Int, childPosition: Int): String {
return itemList[groupPosition][childPosition]
}
override fun getGroupId(groupPosition: Int): Long {
return groupPosition.toLong()
}
override fun getChildId(groupPosition: Int, childPosition: Int): Long {
return childPosition.toLong()
}
override fun hasStableIds(): Boolean {
return true
}
override fun getGroupView(
groupPosition: Int,
isExpanded: Boolean,
convertView: View?,
parent: ViewGroup?,
): View {
var groupView = convertView
if (groupView == null) {
val layoutInflater =
this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
groupView = layoutInflater.inflate(R.layout.medication_list_group, null)
val groupTextView: TextView = groupView.findViewById(R.id.text_group_name)
groupTextView.text = groupList[groupPosition]
} else return groupView
return groupView
}
override fun getChildView(
groupPosition: Int,
childPosition: Int,
isLastChild: Boolean,
convertView: View?,
parent: ViewGroup?
): View {
var childView = convertView
if (childView == null) {
val layoutInflater =
this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
childView = layoutInflater.inflate(R.layout.medication_list_item, null)
childView.findViewById<TextView>(R.id.text_medication_name).text = getChild(groupPosition, childPosition)
} else return childView
return childView
}
override fun isChildSelectable(groupPosition: Int, childPosition: Int): Boolean {
return true
}
}
这是详细视图片段:
class MedicationItemFragment : Fragment() {
private lateinit var medicationName: String
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//get medication name from SafeArgs
arguments?.let {
medicationName = it.getString("medicationName").toString()
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_medication_item, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// get the correct medication data
val medication: Medication = MedicationsListData().getMedication(medicationName)
// populate the view with current medication's data
view.findViewById<TextView>(R.id.text_pharmacodynamics_body).text =
medication.pharmacodynamics
view.findViewById<TextView>(R.id.text_contraindications_body).text =
medication.contraindications
}
companion object {
fun newInstance(): ParametersFragment = ParametersFragment()
}
}
这是提供适配器数据的class:
class GroupListData {
fun getItemData(): List<List<String>> {
return listOf(
listOf("amoxicillin + clavulanate","penicillin","clindamycin","vancomycin"),
listOf("epinephrine","norepinephrine","dopamine"),
listOf("metoprolol","adenosine","amiodarone"),
listOf("metoclopramide")
)
}
fun getGroupData(): List<String> {
return listOf(
"antibiotics",
"vasopressors",
"antiarrhythmics",
"antiemetics"
)
}
}
如有必要,我可以详细说明或解释任何内容。非常感谢任何帮助!
经过仔细阅读,我现在明白问题是回收视图没有正确填充。对此的解决方法是停止回收视图并为每个 child 创建一个新视图:
override fun getChildView(
groupPosition: Int,
childPosition: Int,
isLastChild: Boolean,
convertView: View?,
parent: ViewGroup?
): View {
var childView = convertView
val layoutInflater = this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
childView = layoutInflater.inflate(R.layout.medication_list_item, null)
val medicationName = GroupListData().getItemData()[groupPosition][childPosition]
val medication: Medication = MedicationsListData().getMedication(medicationName)
childView.findViewById<TextView>(R.id.text_medication_name).text = medication.medicationName
if(medication.brandName != "null") {
childView.findViewById<TextView>(R.id.text_brand_name).text = medication.brandName
}
return childView
}
我不认为这是一种解决方案,而是一种变通方法,因为 (non-recycled) 的观看次数可能会导致一些性能问题。但是,如果其他人正在为同样的问题而苦苦挣扎(并且没有预料到性能问题),那么这很有效。
我正在编写一个应用程序来显示药物组、药物及其信息的树视图。本质上,它是药物组的 ExpandableListView,它显示单个药物名称作为 children 视图,并在点击时打开一个包含更多信息的新片段。
我无法用正确的数据填充 child 视图。适配器似乎正确地获取了组数据,并且从日志记录和调试看来 child 数据似乎也被正确传递。但是,ExpandableListView 中 childViews 中的文本仅对我打开的第一组是正确的,接下来的每一组都显示看似随机的内容(打开顺序无关紧要)。 child观看次数正确。详细视图 (onClick) 显示正确的信息,按下后退按钮时,菜单将显示正确的信息(但是,任何新打开的组仍然显示错误的内容)。
我至少进行了 20 轮检查和澄清任何可疑代码,但无济于事。
澄清截图:
list view with two groups expanded
detail view, showing correct info (but not matching that shown in list view)
list view upon returning (notice contents now shown correctly)
这是 ExpandableListAdapter:
class MedicationsListAdapter(
private val context: Context,
private val groupList: List<String>,
private val itemList: List<List<String>>
) : BaseExpandableListAdapter() {
override fun getGroupCount(): Int {
return groupList.size
}
override fun getChildrenCount(groupPosition: Int): Int {
return itemList[groupPosition].size
}
override fun getGroup(groupPosition: Int): List<String> {
return itemList[groupPosition]
}
override fun getChild(groupPosition: Int, childPosition: Int): String {
return itemList[groupPosition][childPosition]
}
override fun getGroupId(groupPosition: Int): Long {
return groupPosition.toLong()
}
override fun getChildId(groupPosition: Int, childPosition: Int): Long {
return childPosition.toLong()
}
override fun hasStableIds(): Boolean {
return true
}
override fun getGroupView(
groupPosition: Int,
isExpanded: Boolean,
convertView: View?,
parent: ViewGroup?,
): View {
var groupView = convertView
if (groupView == null) {
val layoutInflater =
this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
groupView = layoutInflater.inflate(R.layout.medication_list_group, null)
val groupTextView: TextView = groupView.findViewById(R.id.text_group_name)
groupTextView.text = groupList[groupPosition]
} else return groupView
return groupView
}
override fun getChildView(
groupPosition: Int,
childPosition: Int,
isLastChild: Boolean,
convertView: View?,
parent: ViewGroup?
): View {
var childView = convertView
if (childView == null) {
val layoutInflater =
this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
childView = layoutInflater.inflate(R.layout.medication_list_item, null)
childView.findViewById<TextView>(R.id.text_medication_name).text = getChild(groupPosition, childPosition)
} else return childView
return childView
}
override fun isChildSelectable(groupPosition: Int, childPosition: Int): Boolean {
return true
}
}
这是详细视图片段:
class MedicationItemFragment : Fragment() {
private lateinit var medicationName: String
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//get medication name from SafeArgs
arguments?.let {
medicationName = it.getString("medicationName").toString()
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_medication_item, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// get the correct medication data
val medication: Medication = MedicationsListData().getMedication(medicationName)
// populate the view with current medication's data
view.findViewById<TextView>(R.id.text_pharmacodynamics_body).text =
medication.pharmacodynamics
view.findViewById<TextView>(R.id.text_contraindications_body).text =
medication.contraindications
}
companion object {
fun newInstance(): ParametersFragment = ParametersFragment()
}
}
这是提供适配器数据的class:
class GroupListData {
fun getItemData(): List<List<String>> {
return listOf(
listOf("amoxicillin + clavulanate","penicillin","clindamycin","vancomycin"),
listOf("epinephrine","norepinephrine","dopamine"),
listOf("metoprolol","adenosine","amiodarone"),
listOf("metoclopramide")
)
}
fun getGroupData(): List<String> {
return listOf(
"antibiotics",
"vasopressors",
"antiarrhythmics",
"antiemetics"
)
}
}
如有必要,我可以详细说明或解释任何内容。非常感谢任何帮助!
经过仔细阅读,我现在明白问题是回收视图没有正确填充。对此的解决方法是停止回收视图并为每个 child 创建一个新视图:
override fun getChildView(
groupPosition: Int,
childPosition: Int,
isLastChild: Boolean,
convertView: View?,
parent: ViewGroup?
): View {
var childView = convertView
val layoutInflater = this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
childView = layoutInflater.inflate(R.layout.medication_list_item, null)
val medicationName = GroupListData().getItemData()[groupPosition][childPosition]
val medication: Medication = MedicationsListData().getMedication(medicationName)
childView.findViewById<TextView>(R.id.text_medication_name).text = medication.medicationName
if(medication.brandName != "null") {
childView.findViewById<TextView>(R.id.text_brand_name).text = medication.brandName
}
return childView
}
我不认为这是一种解决方案,而是一种变通方法,因为 (non-recycled) 的观看次数可能会导致一些性能问题。但是,如果其他人正在为同样的问题而苦苦挣扎(并且没有预料到性能问题),那么这很有效。