I'm trying to delete a note from a Room Database by calling a method when the user long clicks on the note, I set up the onLongClickListener on the RView adapter:
viewHolder.itemView.setOnCLickListener{
NotesFragment().deleteSingleNote(notesID)
}
On NotesFragment, the method looks like:
fun deleteSingleNote(notesID: Long) {
notesFragmentViewModel.deleteSingleNoteFromDB(notesID)
}
and on the ViewModel the method deletes the note through a coroutine.
The app crashes on long click, saying that the lateinit notesFragmentViewModel had not been initializing, pointing to the onLongCLickListener line, and NotesFragment line I pasted above.
The thing is, the notes are populated on the screen through a NotesFragmentViewModel LiveData variable which contains all the notes, so the ViewModel is very much initialized by the time I long click on the item.
I tried initializing the ViewModel on the adapter, but I got an exception related to ViewModel not being allowed tobe instantialized on something other than a fragment/activity.
This is my first post on SOverflow, so please let me know if I did anything wrong
Inside the OnClickListener
you want to access the NotesFragment
instance which is currently displayed. But with NotesFragment()
you create a new instance of NotesFragment
. Since it will not be attached to any Activity
it's very likely that the notesFragmentViewModel property of the new instance has not been initialized.
So to avoid an Exception
you have to access the correct instance of NotesFragment
. You could introduce a parameter of type NotesFragment
to the constructor of the RecyclerView.Adapter
, but this is considered bad practice.
It's better to let the adapter class have an interface (let's call it ListItemClickedListener
) and a constructor which requires an instance of ListItemClickedListener
as parameter.
interface ListItemClickedListener{
fun singleNoteLongClicked(notesID: Long)
}
Then you can have either NotesFragment
implement ListItemClickedListener
and pass itself to the adapter or you use an anonymous local instance of ListItemClickedListener
.
Inside the adapter:
viewHolder.itemView.setOnCLickListener{
listItemClickListener.singleNoteLongClicked(notesID)
}
In NotesFragment
:
override fun singleNoteLongClicked(notesID: Long){
this@NotesFragment.deleteSingleNote(notesID)
}
See for example this post for an implementation of this pattern.