如何在Fragment中使用LiveData更新Recycler视图?

4

我希望更新我的Recycler View,这样每当我从数据库中删除一行时,它就可以立即更新Recycler View而无需刷新片段。

 override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View?
    {

        var binding:FragmentDisplayBinding = DataBindingUtil.inflate(inflater,R.layout.fragment_display,container,false)

        var view:View = binding.root

        var new_task : FloatingActionButton = view.findViewById(R.id.add_newTask)





        var db = Room.databaseBuilder(context!!,tasksDb:: class.java,"mydb").allowMainThreadQueries().build()
        viewManager = LinearLayoutManager(context)

        recyclerView = view.findViewById(R.id.recyclerView)

        db.task().getAll().observe(this, Observer {
            this.myAdapter = myAdapter(it)
            recyclerView.adapter = myAdapter
            recyclerView.layoutManager = viewManager
        })

我认为我不应该在onCreateView()方法中使用.observe()。那么我需要在代码中做哪些改变?

由于您已经实现了实时数据,因此实现DiffUtil会很好。阅读有关DiffUtils的内容。简而言之,它计算列表中的差异并相应地更新。 - Taseer
2个回答

9

我试图在互联网上找到一些示例解决方案,肯定有人做过,但是没有找到任何一个。我发现很多解决方案要么太简略,要么太详细。所以我会在这里放下你需要的东西。有一个标准化的模式涉及 RecyclerView + LiveData,因此只需遵循此模式即可处理所有 RecyclerView + LiveData 的用法。

片段(Fragment):

override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
): View? {

    ...

    val recyclerView = view.findViewById(R.id.recyclerView)
    val myAdapter = MyAdapter()
    recyclerView.adapter = myAdapter
    // recyclerView.layoutManager = LinearLayoutManager(context) // You need this only if you haven't set it in xml

    db.task().getAll().observe(viewLifecycleOwner, Observer {
        myAdapter.submitList(it)
    })
}

以下是重要的更改:

  • 必须在 onCreateView() 中调用 .observe()。不仅针对这个特定情况,而且通常情况下,只要正确使用 LiveData,就不需要在其他地方调用 .observe()
  • viewLifecycleOwner 是观察 LiveData 所使用的正确 LifecycleOwner。(除非您创建了自定义的 LifecycleOwner
  • 视情况而定,但通常每个RecyclerView 只需实例化一个适配器,即使数据随时间变化。您应该交换数据,而不是整个适配器。


MyAdapter:

MyAdapter 应该实现.submitList() 函数,此函数将被视图使用。

class MyAdapter: RecyclerView.Adapter<ViewHolder>() {

    val myData = mutableListOf<Data>()

    fun submitList(newData: List<Data>) {
        myData.clear()
        myData.addAll(newData)
        notifyDataSetChanged()
    }
}

请注意,notifyDataSetChanged() 是实际上向适配器发出更新视图的信号。
改进:
我认为上述解决方案对于您的问题已经足够好了,前提是您的列表不太大或更新不太频繁。如果您想进一步提高性能和/或可读性,请尝试以下方法:
  • 使用分页库对长列表或无限列表进行分页。
  • 在工作线程中使用DiffUtil进行差异比较,如评论中所建议的那样。
  • 绑定库以减少一些样板代码。

如果我写了这样的代码,你认为在RecyclerView适配器内部,如果我执行currentData = myData[position],然后例如,在onBindViewHolder中通过执行currentData.name=1000来更改数据。这行代码会触发LiveData吗? - Ajay P. Prajapati

1

也许这会有所帮助。

要刷新您在回收站中的项目,您需要使用以下代码:

myAdapter.notifyDataSetChanged(); recyclerview.setAdapter(myAdapter);

在您的情况下,在删除回收视图项的逻辑之后立即编写此方法。


1
不应该鼓励使用notifyDataSetChanged(),因为它非常低效。它会强制Recycler View丢弃当前项并重新绘制,从而使用更多资源。一种更好、更新的方法是使用DiffUtil - Taseer
嗨,Taseer Ahmad。在阅读了您上面提到的链接后,我完全同意DiffUtil将是一个非常好的解决方案。谢谢。 - SaiAbhijit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接