【问题标题】:How to work with LiveData on RecyclerView?如何在 RecyclerView 上使用 LiveData?
【发布时间】:2021-01-14 20:59:53
【问题描述】:

**问题是这样的:我按下按钮删除列表中的一个项目,它被删除了。但是当我旋转屏幕时,列表会重新加载。该列表不保存数据。

LiveData 没有看到变化。如何通过它传递一个带有已删除元素的新列表?我花了 10 个小时解决了这个问题(**

适配器

class ItemAdapter(var context: Context, private var arrayList: MutableList<NumberModel>):RecyclerView.Adapter<ItemAdapter.ItemHolder>() {

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemHolder{

    val itemHolder = LayoutInflater.from(parent.context).inflate(
        R.layout.grid_layout_list_item,
        parent,
        false
    )
    return ItemHolder(itemHolder)
}

override fun onBindViewHolder(holder: ItemHolder, position: Int) {
    var positionOfNumber:NumberModel = arrayList.get(position)
    holder.textOfNumber.text = positionOfNumber.numberOfElement
   holder.button.setOnClickListener {
       var positionForDelete = holder.adapterPosition
       arrayList.removeAt(positionForDelete)
       notifyItemRemoved(positionForDelete)
       notifyItemRangeChanged(positionForDelete,arrayList.size)
   }
}
override fun getItemCount(): Int {
    return arrayList.size
}

class ItemHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    var textOfNumber = itemView.findViewById<TextView>(R.id.numberTextView)
    var button:Button = itemView.findViewById(R.id.buttonClick)
}

}

MainActivity

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    val list = mutableListOf<NumberModel>()
    adapter = ItemAdapter(this,list)
    recyclerView = findViewById(R.id.recyclerViewList)
    gridLayoutManager = GridLayoutManager(applicationContext,2,LinearLayoutManager.VERTICAL,false)
    recyclerView?.layoutManager = gridLayoutManager
    recyclerView?.setHasFixedSize(true)
    recyclerView?.adapter = adapter

    val model= ViewModelProvider(this).get(MainActivityViewModel::class.java)
    model.getListElements().observe(this, Observer {elementsSnapshot ->
        // Received elements from ViewModel
        list.clear()
        // Take new data from snapshot
        list.addAll(elementsSnapshot)
        adapter?.notifyDataSetChanged()
    })
}

视图模型

class MainActivityViewModel : ViewModel() {
private val elementsList: MutableLiveData<MutableList<NumberModel>>

init {
    elementsList = MutableLiveData()
    elementsList.value = setElements()
}
fun getListElements() : LiveData<MutableList<NumberModel>>{
   return elementsList
}

private fun setElements() : MutableList<NumberModel> {
    val itemArrayList:MutableList<NumberModel> = ArrayList()
    itemArrayList.add(NumberModel("1"))
    itemArrayList.add(NumberModel("2"))
    itemArrayList.add(NumberModel("3"))
    itemArrayList.add(NumberModel("4"))
    itemArrayList.add(NumberModel("5"))
    return itemArrayList
}

}

【问题讨论】:

    标签: android-studio kotlin android-livedata android-viewmodel


    【解决方案1】:

    从 ViewModel 返回的变异对象很少是一个好主意。对事件的反应(比如用户点击你的删除按钮)应该在 ViewModel 中完成。这与响应式 UI 样式(数据下降,事件上升)一致,并允许您将逻辑(ViewModel)与 UI 细节(Activity、Adapter)分开。

    您的 ViewModel 可以公开两个元素:

    class MyViewModel {
        private val localElements = MutableLiveData<List<...>>()
    
        val elements: LiveData<List<...>> 
            get() = localElements
    
        fun onElementClicked(index: Int) { 
            // get current value of localElements, make a copy of it with removed value at [index] and publish it to localElements
        }
    }
    

    然后,您可以在您的适配器中公开setElements 方法并调用它以响应viewModel.elements 的更改。您可以将 ViewModel 的实例传递给您的适配器,并在检测到点击时调用 onElementClicked

    这样,您可以将您的 Activity 和 Adapter 视为基本上“无状态”。当配置更改时,有效状态将保留在您的 ViewModel 中。

    PS。 Android 文档建议在构建 Activity/Fragment 期间检索您的 ViewModel 实例:https://developer.android.com/jetpack/guide?authuser=1#build-ui

    【讨论】:

    • 我尝试这样做,但没有任何效果。我将此添加到适配器 var example:MainActivityViewModel = MainActivityViewModel() exp.updateElements(arrayList.size) 并将其添加到 ViewModel fun updateElements(item: Int) { itemArrayList.size == item }
    • 如何从适配器传递一个新列表?使用对象 LiveData ?
    • 您应该将 ViewModel 从您的 Activity 传递给 Adapter,而不是创建它的新实例。为什么要将列表从适配器传递给 ViewModel?记住:data(比如列表)去down(ViewModel -> Adapter via LiveData)和events(比如“user clicked sth”) go up (Adapter -> ViewModel via method call)
    • 我试着听从你的建议,但还是出了点问题,当然是我的错。如果您查看代码并告诉我问题所在,我将非常感激。请github.com/MisterPendragon/AvitoProject
    • 您仍在尝试删除 onClick 回调中的项目。不要这样做,只需调用您的 ViewModel 方法并让它负责更新您的数据
    猜你喜欢
    • 2020-01-01
    • 1970-01-01
    • 2018-11-10
    • 1970-01-01
    • 2020-09-05
    • 2020-03-17
    • 1970-01-01
    • 2019-11-13
    • 1970-01-01
    相关资源
    最近更新 更多