Issue
I have a problem with recycler view. In my previous app, when i get the list for recycler view adapter from database and observe it in my fragment, i used the notifyDataSetChanged() and when i tried to delete a item , view updated successfully. But in this app this does not work and i don't understand why. When i click the delete button the item deleted in database successfully but i can't see it immediatly. When i go to any other fragment and back to this Favourites fragment i see the items deleted. I tried all the options in stackoverflow but still i can't fix it. My Adapter:
class FavouritesAdapter(owner: ViewModelStoreOwner, val favouritesList : ArrayList<Vocabulary>) : RecyclerView.Adapter<FavouritesAdapter.FavouritesViewHolder>() {
val viewModel = ViewModelProvider(owner).get(FavouritesViewModel::class.java)
class FavouritesViewHolder(val binding: FavouritesItemRowBinding) : RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FavouritesViewHolder {
return FavouritesViewHolder(FavouritesItemRowBinding.inflate(LayoutInflater.from(parent.context), parent, false))
}
override fun onBindViewHolder(holder: FavouritesViewHolder, position: Int) {
holder.binding.englishWordTV.text = favouritesList[position].word
holder.binding.turkishWordTV.text = favouritesList[position].translation
holder.binding.deleteButtonRV.setOnClickListener {
viewModel.deleteVocabulary(favouritesList[position])
notifyDataSetChanged()
}
}
override fun getItemCount(): Int {
return favouritesList.size
}
fun updateList(myList : List<Vocabulary>) {
favouritesList.clear()
favouritesList.addAll(myList)
notifyDataSetChanged()
}
}
My problem is in delete button in my recycler row;
holder.binding.deleteButtonRV.setOnClickListener {
viewModel.deleteVocabulary(favouritesList[position])
notifyDataSetChanged()
}
And here is my fragment ;
class FavouritesFragment : Fragment() {
private var _binding: FragmentFavouritesBinding? = null
private val binding get() = _binding!!
private lateinit var favouritesAdapter : FavouritesAdapter
private lateinit var viewModel : FavouritesViewModel
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentFavouritesBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel = ViewModelProvider(this).get(FavouritesViewModel::class.java)
favouritesAdapter = FavouritesAdapter(this, arrayListOf())
viewModel.getAllVocabulariesFromDB()
prepareRecyclerView()
observeFavouritesLiveData()
}
fun prepareRecyclerView(){
binding.favouritesRecyclerView.apply {
layoutManager = LinearLayoutManager(context)
adapter = favouritesAdapter
}
}
fun observeFavouritesLiveData(){
viewModel.favouritesListLiveData.observe(viewLifecycleOwner, Observer {
it?.let {
favouritesAdapter.updateList(it)
}
})
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
Solution
i tried to use the path "button click -> UI sends delete event to VM -> VM updates data -> observer sees new data -> observer calls update with new data" as @cactuctictacs mentioned. I added this lines to my adapter,
lateinit var onDeleteItemClick : ((Vocabulary) -> Unit)
holder.binding.deleteButtonRV.setOnClickListener {
onDeleteItemClick.invoke(favouritesList[position])
notifyItemRemoved(position)
}
and added to my fragment,
fun deleteButtonClicked(){
favouritesAdapter.onDeleteItemClick = {
viewModel.deleteVocabulary(it)
viewModel.getAllVocabulariesFromDB()
observeFavouritesLiveData()
favouritesAdapter.notifyDataSetChanged()
}
}
I hope this is the proper way to do this.
Answered By - Ugur
Answer Checked By - Marie Seifert (JavaFixing Admin)