简体   繁体   中英

NotifyDataSetChanged does not update the RecyclerView correctly

I am trying to implement a fairly basic logic within my recyclerview adapter but notifyDataSetChanged() is giving me quite the headache.

I have a filter method that looks like this:

fun filter(category: Int) {
    Thread(Runnable {
        activeFiltered!!.clear()

        if (category == -1) {
            filterAll()
        } else {
            filterCategory(category)
        }

        (mContext as Activity).runOnUiThread {
            notifyDataSetChanged()
        }
    }).start()
}

where filterAll() and filterCategory() functions are quite easy:

private fun filterAll() {
    activeFiltered?.addAll(tempList!!)
}

private fun filterCategory(category: Int) {
    for (sub in tempList!!) {
        if (sub.category == category) {
            activeFiltered?.add(sub)
        }
    }
}

When I run this code and filter the list by category the activeFiltered list is updated correctly and contains the items I expect, but when notifyDataSetChanged() is run it only cuts the list's range without updating the items.

Is there a way to fix this?

I also tried, instead of notifyDataSetChanged() to use:

activeFiltered!!.forEachIndexed {index, _ ->  notifyItemChanged(index)}

but the problem is still there.

It isn't a threading issue either since I tried putting the whole logic in the main thread and the list still wasn't updated correctly.

This is my onBindViewHolder() :

override fun onBindViewHolder(viewHolder: ActiveViewHolder, pos: Int) {
    sub = activeFiltered!![pos]
    inflateView()

}

This is where I inflate my text, sub is the instance variable set in the onBindViewHolder() :

private fun inflateView() {
        viewHolder.title.text = sub.title
    }

It seems the implementation of onBindViewHolder() is incorrect. In order to update a list item, the passed in viewHolder parameter should be used (not the viewHolder you created in the onCreateViewHolder() ).

The correct implementation should be like

override fun onBindViewHolder(viewHolder: ActiveViewHolder, pos: Int) {
    val sub = activeFiltered!![pos]
    inflateView(viewHolder, sub)
}

private fun inflateView(viewHolder: ActiveViewHolder, sub: <YourDataType>) {
    viewHolder.title.text = sub.title
}

By the way, it is not a good practice to hold something as a member field in order to access it in several methods. Feel free to pass it as arguments to such methods. In the above code I passed the sub as argument and not stored it as a member.

And also it is not necessary to hold the viewHolder that you create in onCreateViewHolder() . We mostly need them in some callback methods (like onBindViewHolder() , etc) and these methods will receive the right viewHolder as arguments.

我认为您是在onBindView()中使用原始数组,而不是经过过滤的数组。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM