问题描述
我的布局中有一个 AutoCompleteTextView
,它将从 API 获取数据,数据返回两个参数,描述和代码,AutoCompleteText
必须可过滤代码和描述。>
为了查看代码和描述,我制作了一个自定义 ArrayAdapter
,我试图实现 Filterable
方法来设置自定义过滤器,该过滤器将检查代码和描述属性。>
问题是,一旦我尝试通过在 AutoCompleteTextView
开始时抛出异常来写入 publishResults
我的应用程序崩溃:java.lang.UnsupportedOperationException
那么我如何为我的 ArrayAdapter 实现自定义过滤器?
这是我的适配器代码:
class FornitoriAdapter(context: Context,resource: Int,private val fornitori: List<Fornitori>) :
ArrayAdapter<Fornitori>(context,resource,fornitori),Filterable {
override fun getView(position: Int,convertView: View?,parent: ViewGroup): View {
val row: View
val holder: ViewHolder
if (convertView == null) {
val inflater = LayoutInflater.from(context)
row = inflater.inflate(R.layout.list_item,parent,false)
holder = ViewHolder(row)
row.tag = holder
} else {
row = convertView
holder = row.tag as ViewHolder
}
val fornitore: Fornitori = fornitori[position]
holder.descrText.text = fornitore.desc
holder.codeText.text = fornitore.cod
return row
}
override fun getItem(position: Int): Fornitori {
return fornitori[position]
}
override fun getCount(): Int {
return fornitori.size
}
private class ViewHolder constructor(row: View) {
val descrText: TextView = row.findViewById(R.id.description)
val codeText: TextView = row.findViewById(R.id.code)
}
override fun getFilter(): Filter {
return customFilter
}
private val customFilter = object : Filter() {
override fun convertResultToString(resultValue: Any?): CharSequence {
return (resultValue as Fornitori).desc
}
override fun performFiltering(constraint: CharSequence?): FilterResults {
val filteredList = mutablelistof<Fornitori>()
if (constraint == null || constraint.isEmpty()) {
filteredList.addAll(fornitori)
} else {
for (item in fornitori) {
if (item.cod.equals(constraint.toString(),ignoreCase = true) || item.desc.toLowerCase(
Locale.ROOT
).startsWith(
constraint.toString().toLowerCase(
Locale.ROOT
)
)
) {
filteredList.add(item)
}
}
}
val results = FilterResults()
results.values = filteredList
return results
}
override fun publishResults(constraint: CharSequence?,filterResults: FilterResults?) {
clear()
val newValues: List<Fornitori> = filterResults?.values as List<Fornitori>
for (element in newValues) {
add(element)
}
if (filterResults.count > 0) {
notifyDataSetChanged()
} else {
notifyDataSetInvalidated()
}
}
}
}
这里是我如何在我的 Fragment 中管理它:
autocompleteFornitore = view.findViewById(R.id.autocompleteFornitore)
val fornitori: List<Fornitori> = listof(Fornitori("001","GAB"),Fornitori("002","TEST"))
val adapter = FornitoriAdapter(requireContext(),R.layout.list_item,fornitori)
autocompleteFornitore.setAdapter(adapter)
autocompleteFornitore.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>?,view: View?,position: Int,id: Long
) {
}
override fun onnothingSelected(parent: AdapterView<*>?) {
}
}
根据需要完整的堆栈跟踪:
2021-03-09 16:05:26.915 31076-31076/it.xxx.xxx E/AndroidRuntime: FATAL EXCEPTION: main
Process: it.xxx.xxx,PID: 31076
java.lang.UnsupportedOperationException
at java.util.AbstractList.remove(AbstractList.java:161)
at java.util.AbstractList$Itr.remove(AbstractList.java:374)
at java.util.AbstractList.removeRange(AbstractList.java:571)
at java.util.AbstractList.clear(AbstractList.java:234)
at android.widget.ArrayAdapter.clear(ArrayAdapter.java:320)
at it.gabtamagnini.visualstock.adapters.FornitoriAdapter$customFilter$1.publishResults(FornitoriAdapter.kt:88)
at android.widget.Filter$ResultsHandler.handleMessage(Filter.java:282)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6518)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
解决方法
它在 ArrayAdapter
的文档中说:
@throws UnsupportedOperationException 如果底层数据集合是不可变的
因此,如果您想使用 MutableList
,您应该将 ArrayAdapter
传入 clear()
,通过将 FornitoriAdapter
构造为 1,或将其转换为 {{ 1}}。