Challenge 2: Interface + @Binds — Solution interface NoteRepository { val notes: Flow> suspend fun refresh() } class NoteRepositoryImpl @Inject constructor( private val dao: NoteDao, private val api: NoteApiService ) : NoteRepository { override val notes: Flow> = dao.getAllNotes() override suspend fun refresh() { try { val remoteNotes = api.getNotes() remoteNotes.forEach { dao.insert(it) } } catch (e: IOException) { // Fall back to cached data, same as Challenge 1 } } } @Module @InstallIn(SingletonComponent::class) abstract class RepositoryModule { @Binds abstract fun bindNoteRepository(impl: NoteRepositoryImpl): NoteRepository } Notes: - NoteRepositoryImpl still has an @Inject constructor (Hilt can build it automatically, since dao and api are both already provided elsewhere) — @Binds doesn't replace that, it just tells Hilt which concrete class to hand out whenever a NoteRepository (the interface) is requested. - RepositoryModule is an abstract class (not an object, unlike the chapter's earlier @Provides-based modules) — @Binds functions must be abstract, since they're declarative mappings, not actual construction code. - Any class elsewhere that requests a "NoteRepository" via constructor injection (a ViewModel, most often) now automatically receives a NoteRepositoryImpl instance — swapping to a different implementation later (e.g. a FakeNoteRepository for testing) only requires changing this one @Binds line, with zero changes needed to the ViewModel.