RecyclerView AsyncListDiffer и состояние согласованности источника данных теряются с onClickListener
У меня есть источник данных (в этом примере это просто var myState: List)
class MainActivity : AppCompatActivity() {
var generation: Int = 0
var myState: List<User> = emptyList()
val userAdapter = UserAdapter {
val index = myState.indexOf(it)
if (index == -1)
println("🔥 not found")
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val recycler = findViewById<RecyclerView>(R.id.rvContent)
recycler.layoutManager = LinearLayoutManager(this)
recycler.adapter = userAdapter
Thread {
while (true) {
generateNewData()
Handler(mainLooper).post {
userAdapter.submit(myState)
}
sleep(3000L)
}
}.start()
}
fun generateNewData() {
generation++
myState = (0..5000).map { User("$generation", it) }
}
}
У меня есть RecyclerView и AsyncListDiffer, подключенный к нему
data class User(val name: String, val id: Int) {
val createdTime = System.currentTimeMillis()
}
data class UserViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
fun bindTo(user: User, action: (User) -> Unit) {
val textView = view.findViewById<TextView>(R.id.title)
textView.text = "${user.name} ${user.id} ${user.createdTime}"
textView.setOnClickListener { action(user) }
}
}
class UserAdapter(val action: (User) -> Unit) : RecyclerView.Adapter<UserViewHolder>() {
val differ: AsyncListDiffer<User> = AsyncListDiffer(this, DIFF_CALLBACK);
object DIFF_CALLBACK : DiffUtil.ItemCallback<User>() {
override fun areItemsTheSame(oldItem: User, newItem: User): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: User, newItem: User): Boolean {
return oldItem == newItem
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder {
return UserViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item, parent, false))
}
override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
val user = differ.currentList[position]
holder.bindTo(user, action = action)
}
fun submit(list: List<User>) {
differ.submitList(list)
}
override fun getItemCount(): Int {
return differ.currentList.size
}
}
У меня OnClickListener привязан к каждому элементу RecyclerView
{
val index = myState.indexOf(it)
if (index == -1)
println("🔥 not found")}
Этот слушатель проверяет, существует ли элемент, по которому был выполнен щелчок, в источнике данных, и, если нет, выводит его на консоль. Каждые несколько секунд данные в источнике изменяются и отправляются в AsyncListDiffer с помощью метода submitList, иногда внутренне он использует другой поток для сопоставления данных и передачи этих различающихся данных в RecyclerView, а это занимает некоторое время; Если я начинаю щелкать элементы без остановки, и событие щелчка происходит в то же время, когда разница вставляет новые данные, то я перехожу в несогласованное состояние.
Итак, как с этим справиться?
- Игнорировать щелчок с несогласованными данными? (Минусы: пользователь может видеть какое-то странное поведение, например, элемент списка не сворачивается / расширяется, не происходит навигации и т. Д.)
- Попытаться найти похожий элемент в новых данных по отдельным полям (позициям и т. Д.) И использовать его? (Минусы: такие же, как 1., но с меньшей вероятностью)
- Блокировать события OnClickListener до тех пор, пока данные не будут согласованы как в Recycler, так и в источнике данных? (минусы: то же, что и выше, а также задержка с действием, выполняемым пользователем, до тех пор, пока данные снова не станут согласованными)
- Что-то другое? Как лучше всего это решить?