【问题标题】:How to make custom Filter for AutoCompleteTextView using custom Adapter?如何使用自定义适配器为 AutoCompleteTextView 制作自定义过滤器?
【发布时间】:2021-03-09 14:26:19
【问题描述】:

我的布局中有一个 AutoCompleteTextView,它将从 API 获取数据,数据返回两个参数,描述和代码,AutoCompleteText 必须可过滤代码和描述。

为了查看代码和描述,我创建了一个自定义的ArrayAdapter,我试图实现Filterable 方法来设置自定义过滤器,该过滤器将检查代码和描述属性。

问题是,一旦我尝试通过在publishResults 开头投射异常来写入AutoCompleteTextView 我的应用程序崩溃: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)

【问题讨论】:

  • 你能告诉我们错误是哪一行抛出的,或者包括完整的堆栈跟踪吗?
  • @HenryTwist 刚刚添加了整个堆栈跟踪
  • @HenryTwist 88 是 clear() 行;
  • 为什么要清除数据?这实际上是错误的原因。
  • @KishanMaurya 通过仅设置 addAll 而没有 clear() 我看到相同的数据

标签: android kotlin android-arrayadapter autocompletetextview


【解决方案1】:

ArrayAdapter 的文档中说:

@throws UnsupportedOperationException 如果底层数据集合是不可变的

因此,如果您想使用clear(),则应该将MutableList 传递到ArrayAdapter,方法是用一个构造FornitoriAdapter,或者用Collection&lt;T&gt;.toMutableList() 转换它。

【讨论】:

  • 我设法得到了过滤器,但现在我遇到了另一个问题,我会为它发布另一个问题
  • 现在您在过滤和删除搜索后没有得到原始列表
  • 是的,您必须单独维护原始列表
  • 我创建了一个关于我的新问题的新问题,您可以查看here
猜你喜欢
  • 2017-09-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多