Update MenuRepository.kt — cache + network
In the code column — the new MenuRepository.kt. Compare it with lesson 5: there it was a single getMenu() going straight to the network. Now getMenu() returns the cache's Flow, and a new refresh() updates the cache from the network (clearAll + insertAll). The constructor now takes two things: (api, dao).
At the bottom of the file — the mappers between entity and domain (both have price: Double, so they're direct):
private fun MenuItemEntity.toDomain() = MenuItem(id, name, description, price, category, imageUrl)
private fun MenuItem.toEntity() = MenuItemEntity(id, name, description, price, category, imageUrl)
MenuViewModel now observes the cache AND kicks off refresh() (both in init):
init {
observeMenu() // subscribe to the cache Flow → Success immediately if the cache is full
refresh() // network → cache → the Flow updates itself
}
private fun observeMenu() = viewModelScope.launch {
repository.getMenu().collect { items ->
if (items.isNotEmpty()) _uiState.value = MenuUiState.Success(items)
}
}
private fun refresh() = viewModelScope.launch {
try { repository.refresh() }
catch (e: Exception) {
if (_uiState.value !is MenuUiState.Success) // only show error if nothing cached
_uiState.value = MenuUiState.Error(e.message ?: "Could not load menu")
}
}
And Koin — the cache becomes a few singles, and MenuRepository gets the DAO:
// coreModule — DB and DAO
single { Room.databaseBuilder(get(), PicaDatabase::class.java, "pica.db").build() }
single { get<PicaDatabase>().menuDao() }
// menuModule — MenuRepository now takes PicaApi AND MenuDao
single { MenuRepository(get(), get()) } // get() = PicaApi, get() = MenuDao
Verify.
1. Run online → the menu loads and is written to the cache.
2. Turn on airplane mode, close and reopen → the menu STILL shows (from the cache).
3. Back online → refresh() quietly updates if anything changed on the server.
Gotcha (main thread). If a DAO method isn't
suspendorFlow, Room crashes:java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.Room forbids touching the DB on the main (UI) thread — a DB call can take a while and "freeze" the interface. The fix is
Flowfor reads andsuspendfor writes (exactly what our DAO does). Never write a synchronous@Queryreturning aListdirectly.