How do you delete a crime?
I put a delete icon on the menu. This is easy. But how do you tell it to delete the item you click on the recyclerview? Further more, when you click on an item, you are presented with a new fragment to edit it.
Anyway, I have tried the selection library, following some tutorials on the Internet, but they all use the key of type Long and the crime uses type UUID. Is there a way to convert it to type Long?
The challenge is asking too much. Please provide more guidance.
I do not want to give away the entire solution, but I will give some hints that will hopefully point you in the right direction. I do not think adding a delete icon to the App Bar is the best way forward. Adding a Button to the list_item_crime.xml is probably a better way forward. Then you could probably hook up something similar to what you did in order to make the navigation work.
As far as the Room portion of this challenge goes, you will not be able to use a Long because of the reason you mentioned. But if you look at Google’s documentation (Accessing data using Room DAOs | Android Developers), you see that Room can accept an @Entity annotated class as a parameter on function to delete an entry. Room will match that entity based on the @PrimaryKey (which is that UUID in Crime). All the other properties do not matter, so you could do something like:
val byeByeCrime = Crime(idToDelete, "", Date(), false)
database.crimeDao().deleteCrime(byeByeCrime)
Thank you for the quick answer. Reading the hints in the book, I thought readers were required to code so that when a user long presses an item a popup menu appears and asks you what to do as we all do with our apps.
This is going to be much much easier than the selection libary.
Finally, I made it work but do you think this is the right way.
I changed the adapter signature, adding onCrimeDelete
class CrimeListAdapter(
private val crimes: List,
private val onCrimeClicked: (crimeId: UUID) → Unit,
private val onCrimeDelete: (crimeId: UUID) → Unit
You are on the right track with the idea that you need to be inside a coroutine scope in order to call suspending functions. And with the repeatOnLifecycle() call, you do have a coroutine scope, but you are calling the crimeListViewModel.deleteCrime(crime) line from within a lambda expression passed into CrimeListAdapter. That lambda expression (onCrimeDelete) is actually invoked inside the CrimeHolder. And where it is invoked is not within a coroutine scope, so you can’t call suspending functions there.
I have a further question about using the recyclerview selection to delete a crime. I have been thinking about this for some time but just not been able to find out why it does not work. Thank you very much for reading.
java.lang.IndexOutOfBoundsException: Empty list doesn’t contain element at index 0.
So I guess the adapter is not updated once it is passed to the selectorTracker.
The selection only works if I passed the StateFlow<List> directly to the adapter like this:
I have never worked with SelectionTracker, so unfortunately I cannot provide any help here. Please let me know if you figure out the solution on your own.
This is my solution for deleting a crime, In CrimeListFragment I declare a var:
private var crimeForDeletion = false
In the menu section I set a Delete icon with this script:
override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
// Handle the menu selection
return when (menuItem.itemId) {
R.id.new_crime -> {
showNewCrime()
true
}
R.id.delete_crime -> {
crimeForDeletion = true
Toast.makeText(
requireContext(),
"SELECT CRIME TO DELETE",
Toast.LENGTH_LONG
).show()
true
}
else -> false
}
}
}, viewLifecycleOwner, Lifecycle.State.RESUMED)
When the adapter is called, there are 2 options, one to delete the crime to be clicked on or to view the crime: