RecyclerView 项目未使用 LiveData 更新
RecyclerView item not updated with LiveData
我有一个使用数据绑定、livedata、room、kotlin koroutines、viewmodel、导航组件和 dagger 的应用程序。
我有一个activity,还有两个片段
ListFragment:在回收站视图中显示项目列表。
DetalFragment:显示项目详细信息,并可以使用保存按钮更新项目的某些字段。
问题是当我从 detailfragment 更新一些字段时,更改在 listfragment 中不可见,但是当我向下和向上滚动时,更改变得可见。
列表片段:
@Inject
lateinit var viewModelFactory: ViewModelProvider.Factory
val viewModel: ListViewModel by viewModels {
viewModelFactory
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val bindings = ListFragmentBinding.inflate(inflater, container, false).apply {
viewmodel = viewModel
}
bindings.lifecycleOwner = this
adapter = ItemsAdapter()
bindings.recyclerView.adapter = adapter
viewModel.items.observe(
viewLifecycleOwner,
Observer { adapter.submitList(it)})
return bindings.root
}
列表视图模型:
var items: LiveData<PagedList<Item>> = repository.items
存储库:
val items<PagedList<Item>>
get()=itemDao.getAllItemsPaged().toLiveData(pageSize=50)
fun getItemFlow(id: String): Flow<Item> = itemDao.getItemFlow(id)
suspend fun updateItem(item: Item) {
itemDao.updateItem(item)
}
ItemDao:
@Query("SELECT * FROM item")
fun getAllItemsPaged(): DataSource.Factory<Int,Item>
@Query("SELECT * FROM itemWHERE id=:id")
fun getItemFlow(id:String):Flow<Item>
@Update
suspend fun updateItem(item:Item)
物品片段:
@Inject
lateinit var viewModelFactory: ViewModelProvider.Factory
val viewModel: ItemViewModel by viewModels {
viewModelFactory
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
viewModel.loadItem(args.itemId)
val bindings = ItemFragmentBinding.inflate(inflater, container, false).apply {
viewmodel = viewModel
buttonSave.setOnClickListener{viewModel. viewModelScope.launch {
viewModel.saveItem()
findNavController().navigateUp()
}}
}
bindings.lifecycleOwner = this
return bindings.root
}
项目视图模型:
var item: LiveData<Item>? = null
fun loadItem(id: String) {
viewModelScope.launch {
item = repository.getItemFlow(id).asLiveData()
}
}
suspend fun saveItem() {
item!!.value!!.someField = "hi"
repository.updateItem(item!!.value!!)
}
问题出在项目适配器中。适配器需要 DiffUtil.ItemCallback
.
的正确实现
在这种情况下:
private val DIFF_CALLBACK = object : DiffUtil.ItemCallback<Contador>() {
// The ID property identifies when items are the same.
override fun areItemsTheSame(oldItem: Contador, newItem: Contador) =
oldItem.id == newItem.id
// Check the properties that can change, or implements the equals method in Item class
override fun areContentsTheSame(
oldItem: Item, newItem: Item) = oldItem.someField == newItem.someField
}
我可以确认 DiffUtil
是正确的。如果使用 RecyclerView
:
的通用方法
ItemListDiffUtil.kt
open class ItemListDiffUtil<T>(private val oldItems: ArrayList<T>, private val newItems: ArrayList<T>) : DiffUtil.Callback(){
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldItems[oldItemPosition] == newItems[newItemPosition]
}
override fun getOldListSize(): Int {
return oldItems.size
}
override fun getNewListSize(): Int {
return newItems.size
}
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldItems[oldItemPosition] == newItems[newItemPosition]
}
}
YOUR_OBJECTAdapter.kt
class YOUR_OBJECTAdapter() : RecyclerView.Adapter<YOUR_OBJECTAdapter.MyViewHolder>() {
class MyViewHolder(viewItem: View) : RecyclerView.ViewHolder(viewItem) {
//your code
}
private var myDataset = ArrayList<YOUR_OBJECT>()
fun setDataset(data : ArrayList<YOUR_OBJECT>){
/*diffUtil*/
val diffCallback = ItemListDiffUtil(myDataset,data)
val diffResult = DiffUtil.calculateDiff(diffCallback)
diffResult.dispatchUpdatesTo(this)
myDataset.clear()
myDataset.addAll(data)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val viewItem = LayoutInflater.from(parent.context).inflate(R.layout.YOUR_OBJECT, parent, false)
return MyViewHolder(viewItem)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
//your code
}
override fun getItemCount(): Int {
return myDataset.size
}
}
我有一个使用数据绑定、livedata、room、kotlin koroutines、viewmodel、导航组件和 dagger 的应用程序。 我有一个activity,还有两个片段
ListFragment:在回收站视图中显示项目列表。
DetalFragment:显示项目详细信息,并可以使用保存按钮更新项目的某些字段。
问题是当我从 detailfragment 更新一些字段时,更改在 listfragment 中不可见,但是当我向下和向上滚动时,更改变得可见。
列表片段:
@Inject
lateinit var viewModelFactory: ViewModelProvider.Factory
val viewModel: ListViewModel by viewModels {
viewModelFactory
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val bindings = ListFragmentBinding.inflate(inflater, container, false).apply {
viewmodel = viewModel
}
bindings.lifecycleOwner = this
adapter = ItemsAdapter()
bindings.recyclerView.adapter = adapter
viewModel.items.observe(
viewLifecycleOwner,
Observer { adapter.submitList(it)})
return bindings.root
}
列表视图模型:
var items: LiveData<PagedList<Item>> = repository.items
存储库:
val items<PagedList<Item>>
get()=itemDao.getAllItemsPaged().toLiveData(pageSize=50)
fun getItemFlow(id: String): Flow<Item> = itemDao.getItemFlow(id)
suspend fun updateItem(item: Item) {
itemDao.updateItem(item)
}
ItemDao:
@Query("SELECT * FROM item")
fun getAllItemsPaged(): DataSource.Factory<Int,Item>
@Query("SELECT * FROM itemWHERE id=:id")
fun getItemFlow(id:String):Flow<Item>
@Update
suspend fun updateItem(item:Item)
物品片段:
@Inject
lateinit var viewModelFactory: ViewModelProvider.Factory
val viewModel: ItemViewModel by viewModels {
viewModelFactory
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
viewModel.loadItem(args.itemId)
val bindings = ItemFragmentBinding.inflate(inflater, container, false).apply {
viewmodel = viewModel
buttonSave.setOnClickListener{viewModel. viewModelScope.launch {
viewModel.saveItem()
findNavController().navigateUp()
}}
}
bindings.lifecycleOwner = this
return bindings.root
}
项目视图模型:
var item: LiveData<Item>? = null
fun loadItem(id: String) {
viewModelScope.launch {
item = repository.getItemFlow(id).asLiveData()
}
}
suspend fun saveItem() {
item!!.value!!.someField = "hi"
repository.updateItem(item!!.value!!)
}
问题出在项目适配器中。适配器需要 DiffUtil.ItemCallback
.
在这种情况下:
private val DIFF_CALLBACK = object : DiffUtil.ItemCallback<Contador>() {
// The ID property identifies when items are the same.
override fun areItemsTheSame(oldItem: Contador, newItem: Contador) =
oldItem.id == newItem.id
// Check the properties that can change, or implements the equals method in Item class
override fun areContentsTheSame(
oldItem: Item, newItem: Item) = oldItem.someField == newItem.someField
}
我可以确认 DiffUtil
是正确的。如果使用 RecyclerView
:
ItemListDiffUtil.kt
open class ItemListDiffUtil<T>(private val oldItems: ArrayList<T>, private val newItems: ArrayList<T>) : DiffUtil.Callback(){
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldItems[oldItemPosition] == newItems[newItemPosition]
}
override fun getOldListSize(): Int {
return oldItems.size
}
override fun getNewListSize(): Int {
return newItems.size
}
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldItems[oldItemPosition] == newItems[newItemPosition]
}
}
YOUR_OBJECTAdapter.kt
class YOUR_OBJECTAdapter() : RecyclerView.Adapter<YOUR_OBJECTAdapter.MyViewHolder>() {
class MyViewHolder(viewItem: View) : RecyclerView.ViewHolder(viewItem) {
//your code
}
private var myDataset = ArrayList<YOUR_OBJECT>()
fun setDataset(data : ArrayList<YOUR_OBJECT>){
/*diffUtil*/
val diffCallback = ItemListDiffUtil(myDataset,data)
val diffResult = DiffUtil.calculateDiff(diffCallback)
diffResult.dispatchUpdatesTo(this)
myDataset.clear()
myDataset.addAll(data)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val viewItem = LayoutInflater.from(parent.context).inflate(R.layout.YOUR_OBJECT, parent, false)
return MyViewHolder(viewItem)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
//your code
}
override fun getItemCount(): Int {
return myDataset.size
}
}