I recently came up with the idea to optimize my application by changing items dynamically instead of notifyDataSetChanged to speed things up a bit, and dynamic changes can also animate them.

The old code:

private fun listItemChanged(v: View? = null) { ((v ? : view)!! .list.adapter as RMAdapter).let { it.data = getNewData() it.notifyDataSetChanged() } }Copy the code

The new code:

private fun listItemChanged(v: View? = null) { ((v ? : view)!! .list.adapter as RMAdapter).let { val newData = getNewData() val diffResult = DiffUtil.calculateDiff(DiffCallBack(it.data, newData),true)
        diffResult.dispatchUpdatesTo(it)
        it.data = newData
    }
}
Copy the code

As you can see, something called DiffUtil is used here, which comes with the official Support V7 package. The function is to detect the difference between two data sets and then dispatchUpdatesTo help you call the corresponding dynamic change item method in Adapter. The principle is to use a 1986 Myers difference algorithm to make the difference check very fast. The official data is that 50 changes out of 1000 items were detected in android 6.0 Nexus 5X in only 3.5ms. The official page

I won’t go into details about how to use it, because that’s not the topic of this article.

So… Everything looks good so far?

pit

There is no problem with deletion. The problem is that items are misplaced after deletion. (It actually took me a while to realize that it was a dislocation and not some other weird thing)

Immediately run to onBindViewHolder and set a breakpoint

Override fun onBindViewHolder(holder: MyViewHolder, position: Int) {holder. ItemView. SetOnClickListener {openChatActivity (data [position] grokid) / / here set breakpoints and found the position for 1}}Copy the code

Delete the first item and position should be 0, then I am confused. Is this an official bug?

I searched some blogs on the Internet and found no solution. Some people even refresh notifyDataSetChanged after using DiffUtil (I:….).

To solve

Of course I finally solved it, otherwise there would have been no article

After sleeping off, I suddenly noticed the name onBindViewHolder, which is only called when setting the layout. And when you set up the layout, this is actually in second place. Changing the item dynamically does not reset the entire table as notifyDataSetChanged does, so the old **position** is used on the new **data** table.

The problem is easily solved by writing down the values at the beginning and ignoring subsequent changes to the data table

Code:

override fun onBindViewHolder(holder: MyViewHolder, position: Int) {val grokid = data [position] grokid / / add the line holder. ItemView. SetOnClickListener {openChatActivity (grokid)}}Copy the code

At this point, the problem is solved and you can enjoy the animation happily


The first time to write an article, please give me more advice!