If a crime is changed on CrimeDetailFragment
and the app’s process is subsequently killed by the OS before navigating back to CrimeListFragment
, that changed crime doesn’t get saved in the database because CrimeDetailViewModel.onCleared()
doesn’t get called.
The issue is that CrimeDetailViewModel.updateCrime
function doesn’t go as far as saving the changes made to the database, but instead only updates _crime
stateflow in the viewmodel.
Also does anyone agree with me that this breaks the practice/principle of single source of truth of data? At any given time we cannot say for certain if the source of crime in CrimeDetailFragment
is the database or an updated version in the viewmodel. Another way to look at it is that _crime
in the viewmodel has two sources of its value; (1) the repository (ultimately the database) and (2) a direct mutation in updateCrime
function.
The way I dealt with this issue is as follows:
- Starting at
CrimeDao
, change the return type ofgetCrime(Int)
toFlow<Crime>
fun getCrime(id: UUID): Flow<Crime>
CrimeRepository
doesn’t change.- In
CrimeDetailViewModel
observe thisFlow<Crime>
in theinit
blockinit { viewModelScope.launch { crimeRepository.getCrime(crimeId).collect { _crime.value = it } } }
- Also in
CrimeDetailViewModel
changeupdateCrime
function tofun updateCrime(onUpdate: (Crime) -> Crime) = _crime.value?.let { oldCrime -> val newCrime = onUpdate(oldCrime) crimeRepository.updateCrime(newCrime) }
If this turns out to be a bug - and I am not just missing something (which is very likely), I suggest the book leaves this bug in place and makes it an end-of-chapter challenge to deal with it. I certainly enjoyed it and was very proud of my self when I managed to make it work.
Aside:
Please note the above updateCrime
function hasn’t been tested because I refactored my own code further such that the function simply becomes
fun updateCrime(crime: Crime) = crimeRepository.updateCrime(crime)
This refactoring was to deal with an issue mentioned on page 295
This might seem like a strange place to set a
View.onClickListener
, but …
I completely agree with the book as updateUi
function should only update the UI. Is anyone interested in discussing this issue further in a separate topic?