Observer 中的 DiffUtil 未刷新视图调用 android kotlin [英] DiffUtil not refreshing view in Observer call android kotlin

查看:90
本文介绍了Observer 中的 DiffUtil 未刷新视图调用 android kotlin的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

嘿,我正在将 diff util 与 ListAdapter 一起使用.列表的更新有效,但我只能通过滚动列表来查看这些新值,即使不回收视图(滚动时),我也需要查看更新,就像 notifyItemChanged() 一样.我尝试了这个答案中的所有内容 ListAdapter not updated item in RecyclerView 只对我有用notifyItemChanged 或重新设置适配器.我正在添加一些代码.请问有人知道如何解决这个问题吗?

Hey I am using diff util with ListAdapter. The updating of list works but I can only see those new values by scrolling the list, I need to view the updates even without recycling the view (when scrolling) just like notifyItemChanged(). I tried everything inside this answer ListAdapter not updating item in RecyclerView only working for me is notifyItemChanged or setting adapter again. I am adding some code. Please someone know how to fix this problem?

数据和枚举类

data class GroupKey(
    val type: Type,
    val abc: Abc? = null,
    val closeAt: String? = null
)

data class Group(
    val key: GroupKey,
    val value: MutableList<Item?> = ArrayDeque()
)

enum class Type{
  ONE,
  TWO
}

data class Abc(
    val qq: String? = null,
    val bb: String? = null,
    val rr: RType? = null,
    val id: String? = null
)

data class RType(
    val id: String? = null,
    val name: String? = null
)


data class Item(
    val text: String? = null,
    var abc: Abc? = null,
    val rr: rType? = null,
    val id: String? = null
)

viewmodel.kt

var list: MutableLiveData<MutableList<Group>?> = MutableLiveData(ArrayDeque())

 fun populateList(){
  // logic to call api 
   list.postValue(data)
 }


 fun addItemTop(){
  // logic to add item on top
  list.postValue(data)
 }

内部视图模型我正在通过视图模型函数内部的api调用填充数据并将值返回到列表.还有另一个函数,它的项目在列表顶部插入,这就是为什么使用 ArrayDeque

inside view model I am filling data by api call inside viewmodel function and return value to list. Also another function which item is inserting at top of list so that's why is used ArrayDeque

现在我正在添加嵌套的 reyclerview diff util 回调.

Now I am adding nested reyclerview diff util callback.

FirstAdapter.kt

class FirstAdapter :
    ListAdapter<Group, RecyclerView.ViewHolder>(comp) {

    companion object {
        private val comp = object : DiffUtil.ItemCallback<Group>() {
            override fun areItemsTheSame(oldItem: Group, newItem: Group): Boolean {
                return oldItem == newItem
            }

            override fun areContentsTheSame(oldItem: Group, newItem: Group): Boolean {
                return ((oldItem.value == newItem.value) && (oldItem.key == newItem.key))
            }
        }
    }
 ......... more function of adapter
}

FirstViewHolder

val adapter = SecondAdapter()
binding.recyclerView.adapter = adapter
adapter.submitList(item.value)

SecondAdapter.kt

class SecondAdapter : ListAdapter<Item, OutgoingMessagesViewHolder>(comp) {

    companion object {
        private val comp = object : DiffUtil.ItemCallback<Item>() {
            override fun areItemsTheSame(oldItem: Item, newItem: Item): Boolean {
                return oldItem.id == newItem.id
            }

            override fun areContentsTheSame(oldItem: Item, newItem: Item): Boolean {
                return ((oldItem.rr == newItem.rr) &&
                        (oldItem.text == oldItem.text) && (oldItem.abc == newItem.abc))
            }
        }
    }
 ..... more function
}

Activity.kt

 viewModel.list.observe(this, { value ->
            submitList(value)
 })

private fun submitList(list: MutableList<Group>?) {
        adapter?.submitList(list)
 //       adapter?.notifyDataSetChanged()
}

我 100% 确定我的列表正在更新,并且当我添加新列表时,我的观察员正在调用.我通过调试视图调试它.但问题是我只能通过滚动列表来查看这些新值,即使不回收视图(滚动时),我也需要查看更新,就像 notifyItemChanged()

I am 100% sure that my list is updating and my observer is calling when my new list is added. I debug that through debug view. But problem is I can only see those new values by scrolling the list, I need to view the updates even without recycling the view (when scrolling) just like notifyItemChanged()

更新

viewmodel.kt

class viewModel : BaseViewModel(){
    
 var list: MutableLiveData<MutableList<Group>?> = MutableLiveData()
//... more variables...


 fun fetchData(context: Context) {
        viewModelScope.launch {
            val response = retroitApiCall()
                response.handleResult(
                    onSuccess = { response ->
                                              
                    list.postValue(GroupData(response?.items, context))
                    },
                    onError = { error ->
                       Log.e("error" ,"$error")
                    }
                )
            }
        }
    }

 internal fun GroupData(items: List<CItem>?, context: Context): MutableList<Group> {
        val result: MutableList<Group> = MutableList()

        items?.iterator()?.forEach { item ->
        // adding item in list by add function and then return list.
        return result
    }


    private fun addItemOnTop(text: String) {
         list.value?.let { oldlist ->
          // logic to add items on top of oldlist variable
           if(top != null){
              oldlist.add(0,item)
           }else{
               val firstGroup = oldlist[0]
               firstGroup.value.add(item)
           }
          list.postValue(oldlist)
         }
    }
}

我正在使用 sealed 类这样的东西,但不是这个 示例.调用 api 时的类似内容 Retrofit Example.我给你的两个链接都是例子.我在我的视图模型中使用了什么.

I am using sealed class something like this but not this one Example. And Something similar to these when call api Retrofit Example. Both link I am giving you example. What I am using in my viewmodel.

推荐答案

我不知道发生了什么,但我可以告诉你两件引起我注意的事情.

I don't know what's going on, but I can tell you two things that caught my attention.

  override fun areItemsTheSame(oldItem: Group, newItem: Group): Boolean {
      return oldItem == newItem
  }

您不是在比较项目是否相同,而是在比较项目及其内容是否相同.您没有像在第二个适配器中那样的 ID 吗?

You're not comparing if the items are the same, you're comparing the items and their contents are the same. Don't you have an Id like you did in your second adapter?

我可能会检查 oldItem.key == newItem.key.

您链接的答案所示,submitList 有一个非常奇怪的逻辑,它比较实际列表的引用是否相同,如果相同,它什么都不做.

As indicated in the answer you linked, submitList has a very strange logic where it compares if the reference of the actual list is the same, and if it is, it does nothing.

在您的问题中,您没有显示列表的来源(它是通过似乎是 liveData 或 RXJava 的内容观察到的),但是构建列表的来源不可见.

In your question, you didn't show where the list comes from (it's observed through what appears to be liveData or RXJava), but the souce of where the list is constructed is not visible.

换句话说:

// P S E U D O   C O D E
val item1 = ...
val item2 = ...
val list1 = mutableListOf(item1, item2)

adapter.submitList(list1) // works fine
item1.xxx = ""
adapter.submitList(list1) // doesn't work well.

为什么?

不幸的是,submitList源代码向我们展示了对列表的相同引用,如果,不计算差异.这实际上不是在适配器上,而是在 AsyncListDiffer 上,由 ListAdapter 内部使用.这是不同的责任来触发计算.但如果列表引用相同,则不同,它会默默地忽略它.

WHY?

Unfortunately, submitList's source code shows us that if the reference to the list is the same, the diff is not calculated. This is really not on the adapter, but rather on AsyncListDiffer, used by ListAdapter internally. It is this differ's responsibility to trigger the calculation(s). But if the list references are the same, it doesn't, and it silently ignores it.

我怀疑您没有创建新列表.这种相当无证的和沉默行为弊大于利,因为通常情况下,开发人员不希望复制提供给对象的列表,该对象的目的和承诺是提供神奇地"(更重要的是,自动)计算它与前一个之间的差异.

My suspicion is that you're not creating a new list. This rather undocumented and silent behavior hurts more than it helps, because more often than not, developers aren't expecting to duplicate a list supplied to an object whose purpose and promise is to offer the ability to "magically" (and more importantly, automatically) calculate its differences between the previous.

我理解他们为什么这样做,但我会至少发出日志警告,表明您提供相同的列表.或者,如果您想避免污染已经被污染的 logCat,那么至少要更加明确在其官方文档中.

I understand why they did it, but I would have at the very least emitted a log WARNING, indicating you're supplying the same list. Or, if you want to avoid polluting the already polluted logCat, then at least be much more explicit about it in its official documentation.

唯一的提示就是这个简单的短语:

The only hint is this simple phrase:

当新列表可用时,您可以使用 submitList(List).

you can use submitList(List) when new lists are available.

这里的关键是新列表这个词.所以不是带有新项目的同一个列表,而是一个新的List引用(无论项目是否相同).

The key here being the word new lists. So not the same list with new items, but simply a new List reference (regardless of whether the items are the same or not).

我首先修改你的 submitList 方法:

I'd start by modifying your submitList method:

private fun submitList(list: MutableList<Group>?) {
        adapter?.submitList(list.toMutableList())
}

更改是创建您收到的列表的副本:list.ToMutableList().这样 AsyncListDiffer 对列表相等性的检查将返回 false 并且代码将继续.

The change is to create a copy of the list you receive: list.ToMutableList(). This way the AsyncListDiffer's check for list equality will return false and the code will continue.

不幸的是,我不知道您的代码发生了什么;我向你保证 ListAdapter 是有效的,因为我自己每天都在使用它;如果你认为你发现了一个有问题的案例,我建议你创建一个小的原型并将它发布到 github 或类似的地方,以便我们可以复制它.

Unfortunately, I don't know what is going on with your code; I assure you that ListAdapter works, as I use it myself on a daily basis; If you think you've found a case where there are problems with it, I suggest you create a small prototype and publish it on github or similar so we can reproduce it.

我将从在关键区域使用调试/断点开始:

I would start by using debug/breakpoints in key areas:

  1. 视图模型;从您返回"的列表中写下参考.
  2. DiffUtil 方法,是否调用了 diffUtil?
  3. 您的 submitList() 方法中的列表引用是否与您在 ViewModel 中的引用相同?
  1. ViewModel; write down the reference fromthe list you "return".
  2. DiffUtil methods, is diffUtil being called?
  3. Your submitList() method, is the list reference the same as the one you had in your ViewModel?
  4. etc.

你需要深入挖掘,直到你发现谁没有做什么.

You need to dig a bit deeper until you find out who is not doing what.

这篇关于Observer 中的 DiffUtil 未刷新视图调用 android kotlin的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆