具有DiffUtil和LiveData的RecyclerView

问题描述

我已经坚持了几天,可以在使用DiffUtil设置RecylerView(RV)方面真的可以使用一些帮助和理解,似乎我尝试无法使RV更新。我将回顾我所拥有的一切,希望有人可以阐明我在做错什么。

应用启动

  • 创建ViewModel,
    • 然后,将LiveDataList填充到ViewModel中。
  • RV已实例化
    • 将LayoutManager和ListAdapter应用于RV。
  • ItemTouchHelper附加到RecyclerView,允许向左滑动时从LiveDataList中删除项目。
  • 观察到LiveDataList,我的理解是,当列表发生更改时,如果原始提交的列表与修改后的列表之间存在差异,则观察者会将列表提交到AdapterList并将其与旧列表进行比较。 AdapterList将更新RecyclerView。

为什么在从LiveDataList列表中添加或删除项目时未调用观察者进行更新。

class MainActivity : AppCompatActivity() {
    var myAdapter = RVAdapter()
    private lateinit var viewModel: MyViewModel()

    override fun onCreateView(savedInstanceState: Bundle? ) {
        super.onCreate(savedInstanceState)
        // Initialize the ViewModel,that stores the userList. 
        viewModel = ViewModelProvider(this).get(MyViewModel::class.java)
        // Creates list of users
        addUser()

        // Link an RV object to view
        val rv = findViewById<RecyclerView>(R.id.recycler_view)
        // apply RV Settings. 
        rv.apply {
            layoutManager = LinearLayoutManager(baseContext,LinearLayoutManager.VERTICAL,false)
            adapter= myAdapter
        }

        ItemTouchHelper(object : ItemTouchHelper.SimpleCallback(0,ItemTouchHelper.LEFT) {
             override fun onMove(...) {
                 // move items isn't used. 
             }

             override fun onSwipe(viewHolder: ViewHolder,direction: Int) {
                 // When I swipe a second item,the app crashes.
                 val editList: MutableList<User>? = viewModel.usersList?.value as MutableList<User>?
                 editList?.removeAt(viewHolder.adapterPosition)
                 viewModel.usersList?.postValue(userList)
             }
        }).attachtoRecyclerView(rv)
     
        // The observer will run after swiping an item but the UI doesn't update. 
        viewModel.usersList?observe(this,Observer {
            it?.let {
                // Should update list but it doesn't
                myAdapter.submitList(it)
            }
    }

    private fun addUser() {
        // Shouldn't there be away to add Items directly to list in ViewModel.
        val newList: MutableList<User> = mutableListOf()
        newList.add(User("Shawn",1)
        newList.add(User("Shannon",2)
        newList.add(User("Don",3)

        viewModel.userList?.postValue(newList)
}

数据类:这是非常基本的,这里没有发生太多事情。

data class User(val name: String,val accountNumber: Int) {
}

ViewModel:MyViewModel仅存储MutableLiveDat

class MyViewModel : ViewModel() {
    val usersList: MutableLiveData<List<User>>? = MutableLiveData() 
}

RecycleView适配器

class RVAdapter : ListAdapter<User,RVAdapter.ViewHolder>(MyDiffCallback() {
    
    // This DiffUtil class never gets called not even on startup.
    class MyDiffCallback: DiffUtil.ItemCallback<User>() {
        override fun areItemsTheSame(oldItem: User,newItem: User): Boolean {
            return oldItem.name == newItem.name
        }

        override fun areContentsTheSame(oldItem: User,newItem: User): Boolean {
            return oldItem == newItem
        }

    }

    ... Rest of RV is working fine but can be included if it's helpful.  
}

从LiveData列表中删除或添加项目时,观察者会将修改后的列表传递给ListAdapter怎么办?

包含StackTrace 索引出站。

2020-10-05 20:14:16.538 19042-19042/com.example.practicerecyclerview2 E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.practicerecyclerview2,PID: 19042
    java.lang.IndexOutOfBoundsException: Index: 2,Size: 2
        at java.util.ArrayList.remove(ArrayList.java:503)
        at com.example.practicerecyclerview2.MainActivity$onCreate$2.onSwiped(MainActivity.kt:100)
        at androidx.recyclerview.widget.ItemTouchHelper$4.run(ItemTouchHelper.java:712)
        at android.os.Handler.handleCallback(Handler.java:883)
        at android.os.Handler.dispatchMessage(Handler.java:100)
        at android.os.Looper.loop(Looper.java:214)
        at android.app.ActivityThread.main(ActivityThread.java:7356)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)

解决方法

ListAdapter未更新的原因是,由于您已对其进行了修改,因此无法在您提交的列表中找到差异。这样,notifyDataChanged()方法不会被调用,并且您再次滑过IndexOutOfBoundsException,因为该项目已不存在。

解决方法是修改并提交列表的副本

override fun onSwipe(viewHolder: ViewHolder,direction: Int) {
    val editList: MutableList<User>? = viewModel.usersList?.value as MutableList<User>?
    val editListCopy = editList?.toMutableList()
    editListCopy?.removeAt(viewHolder.adapterPosition)
    viewModel.users?.postValue(editListCopy)
}

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...