设置过滤结果后,Recyclerview 未显示任何项目

时间:2021-07-29 09:58:34

标签: android android-recyclerview android-filterable

由于嵌套滚动问题,我不得不将带有过滤器功能的 ArrayAdapter 重新制作为 RecyclerView Adapter。但是在我重新制作后,RecyclerView 为空,但 adapter.itemCount 返回正确的值。问题是在我调用 adapter.notifyDataSetChanged() 后,它没有调用 onCreateViewHolderonBindViewHolder 函数。

class ZoneViewHolder(val root: ViewGroup): RecyclerView.ViewHolder(root) {

    fun bind(
            zone: FlightZone,
            manageZoneCheck: (View)-> Unit,
            maybeAutoselectZone: (View) -> Unit){
        root.setOnClickListener {
            manageZoneCheck(root.find(R.id.check))
        }
        root.find<View>(R.id.check).also { check->
            check.setOnClickListener {
                manageZoneCheck(check)
            }

            //autoselect zone if it was previously picked (after search reset)
            maybeAutoselectZone(check)
        }
        root.findText(R.id.zoneNum).text = zone.name
        root.findText(R.id.zoneName).apply {
            isSelected = true
            text = zone.radarInfo
        }
        root.findText(R.id.separator).setVisibleNotGone(zone.radarInfo != null)
    }

}

class ZoneListAdapter(
        private val ctx: Context,
        private val inflater: LayoutInflater,
        private val zoneView: Int,
        private val zoneList: List<FlightZone>,
        private var list: MutableList<FlightZone>,
        private val pickedZones: List<FlightZone>,
        private val onZoneChecked: (FlightZone, Boolean) -> Unit,
        private val onAllZonesChecked: (Boolean) -> Unit,
        private val onFilterDone: (List<FlightZone>) -> Unit
): RecyclerView.Adapter<ZoneViewHolder>(), Filterable{

    override fun getItemCount() = list.size

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ZoneViewHolder {
        return ZoneViewHolder(inflater.inflate(zoneView, parent, false) as ViewGroup)
    }

    override fun onBindViewHolder(vh: ZoneViewHolder, position: Int) {
        val zone = list[position]
        App.log("ZoneListAdapter: onBindView: ${list.size}")
        vh.bind(
                zone,
                manageZoneCheck = { check->
                    manageZoneCheck(check, zone)
                },
                maybeAutoselectZone = {check->
                    App.log("ZoneListAdapter: alreadyPicked: ${pickedZones.size}")
                    if (pickedZones.find { it.id == zone.id } != null) check.callOnClick()
                }
        )
    }

    /**
     * Custom Filter implementation for custom suggestions we provide.
     */
    data class ZoneFilterable(val zone: FlightZone, val prefixLength: Int)
    internal var tempItems: MutableList<FlightZone> = zoneList.toMutableList()
    internal var suggestions: MutableList<ZoneFilterable> = mutableListOf()
    internal val sharedCounterLock = Semaphore(1)
    private var filter = object : Filter(){
        override fun performFiltering(constraint: CharSequence?): FilterResults {
            return if (constraint != null) {
                sharedCounterLock.acquire()
                suggestions.clear()

                filterByName(constraint)
                suggestions.sortedByDescending { it.prefixLength }

                val filterResults = FilterResults()
                filterResults.values = suggestions
                filterResults.count = suggestions.size
                sharedCounterLock.release()
                filterResults
            } else {
                FilterResults()
            }
        }

        private fun filterByName(constraint: CharSequence?){
            tempItems.forEach {
                val zoneName = it.name.toLowerCase(Locale.getDefault())
                val zoneNameNonAccent = zoneName.removeDiacritics()
                val query = constraint.toString().toLowerCase(Locale.getDefault())
                val queryNonAccent = query.removeDiacritics()
                App.log("FlightZonePicker filter zone name non-accent: $zoneNameNonAccent")

                if (zoneNameNonAccent.contains(queryNonAccent)) {
                    val prefix = zoneName.commonPrefixWith(query)
                    suggestions.add(ZoneFilterable(it, prefix.length))
                }
            }
        }

        override fun publishResults(constraint: CharSequence?, results: FilterResults) {
            if (results.count > 0) {
                list.clear()
                val filterList = results.values as? List<Any?>
                var resultList = mutableListOf<FlightZone>()

                GlobalScope.launch(Dispatchers.Main) {
                    val resultListAsync = async {
                        withContext(Dispatchers.Default) {
                            val list = mutableListOf<FlightZone>()
                            sharedCounterLock.acquire()
                            val iter = filterList?.iterator()
                            iter?.let {
                                while (iter.hasNext()) {
                                    val item = iter.next()
                                    (item as ZoneFilterable).let { (zoneEntity) -> list.add(zoneEntity) }
                                }
                            }
                            sharedCounterLock.release()
                            return@withContext list
                        }
                    }
                    resultList = resultListAsync.await().take(10).toMutableList()
                    App.log("ZoneListAdapter: Results: ${resultList.size}")
                    list.addAll(resultList)
                    onFilterDone.invoke(resultList)
                }
            }
        }
    }

    init {
        tempItems = zoneList.toMutableList()
    }

    override fun getFilter(): Filter {
        return filter
    }
}

MainClass:
zoneListRecycleView = findViewById(R.id.zoneResults)
zoneListAdapter = ZoneListAdapter(
                        ctx,
                        f.layoutInflater,
                        R.layout.zone_pick_item,
                        zoneList,
                        filteredZones,
                        pickedZones,
                        onZoneChecked = {
                            zone, isPicked ->
                            pickedZones.apply {
                                if (isPicked){
                                    if (find { it.id == zone.id } == null) add(zone)
                                } else {
                                    if (find { it.id == zone.id } != null) remove(zone)
                                }
                            }
                            zoneListAdapter.notifyDataSetChanged()
                        },
                        onAllZonesChecked = {ischecked->
                            pickedZones.apply {
                                clear()
                                if(ischecked) addAll(zoneList)
                            }
                            zoneListAdapter.notifyDataSetChanged()
                        },
                        ::onFilterResult
                )
zoneListRecycleView.adapter = zoneListAdapter

private fun onFilterResult(list: List<FlightZone>){
        filteredZones = list.toMutableList()
        zoneListAdapter.notifyDataSetChanged()
        App.log("ZonelistAdapter: count = ${zoneListAdapter.itemCount}")
}

更新:

我将 Adapter 更改为 ListAdapter 并将 publishResults 函数更改为

resultList = resultListAsync.await().take(10).toMutableList()
onFilterDone.invoke(resultList)

在我的父类中,我调用:

private fun onFilterResult(list: List<FlightZone>){
        filteredZones = list.toMutableList()
        zoneListAdapter.submitList(filteredZones)
        App.log("ZonelistAdapter: filteredList = ${filteredZones.size}")
        App.log("ZonelistAdapter: count = ${zoneListAdapter.itemCount}")
}

日志:

app: ZonelistAdapter: filteredList = 10
app: ZonelistAdapter: count = 0

适配器仍有一些问题。因此过滤器功能按预期工作,但适配器和回收站视图由于某种原因没有显示项目。

0 个答案:

没有答案