如何使用自定义适配器为 AutoCompleteTextView 制作自定义过滤器?

How to make custom Filter for AutoCompleteTextView using custom Adapter?

我的布局中有一个 AutoCompleteTextView,它将从 API 获取数据,数据 returns 两个参数,描述和代码,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.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 if the underlying data collection is immutable

因此,如果您想使用 clear(),您应该将 MutableList 传递给 ArrayAdapter,方法是用一个构造 FornitoriAdapter,或者将其转换为Collection<T>.toMutableList().