Save User State

Sep 10 2024 · Kotlin 1.9, Android 14, Android Studio Koala | 2024.1.1

Lesson 06: CRUD Operations

Demo: Create & Read Notes from Room Database

Episode complete

Play next episode

Next
Transcript

In this section, you’ll create a repository that performs some of the CRUD operations from your database.

Open the starter project for this lesson. Navigate to com.kodeco.android.devscribe. Create a new package and name it repository. Inside the package, create a new interface named NotesRepository, and add the following code to the interface body:

suspend fun saveNote(noteEntity: NoteEntity)
fun getNotes(): Flow<List<NoteEntity>>

Remember to import your dependencies.

In the code above, you have a NotesRepository interface that has two functions. The first function, saveNote, is a suspend function that takes a NoteEntity object as a parameter. The second function, getNotes, returns a Flow of List<NoteEntity>.

Next, you’ll create an implementation of the NotesRepository interface. Still, inside the NotesRepository.kt file, add the following code:

class NotesRepositoryImpl(
  private val ioDispatcher: CoroutineDispatcher,
  private val notesDao: NotesDao
): NotesRepository {
  override suspend fun saveNote(noteEntity: NoteEntity) {
    withContext(ioDispatcher) {
      notesDao.insert(noteEntity)
    }
  }

  override fun getNotes(): Flow<List<NoteEntity>> {
    return notesDao.getNotes()
  }
}

  To explain the code above:

 - The NotesRepositoryImpl class implements the NotesRepository interface. In the constructor, you have two parameters, ioDispatcher and notesDao. The ioDispatcher is a CoroutineDispatcher that you’ll use to run the database operations on a background thread. The notesDao is an instance of the NotesDao class that you’ll use to interact with the database.   - The saveNote function is a suspend function that takes a NoteEntity object as a parameter. Inside the function, you call the insert function on the notesDao object to insert the note into the database.   - The getNotes function returns a Flow of List<NoteEntity>. Inside the function, you call the getNotes function on the notesDao object to get all the notes from the database.

Next, you’ll add this class to your Koin modules together with the CoroutineDispatcher module. Head over to the Modules.kt file inside the di package, and add the following code below your roomDatabaseModule:

val dispatcherModule = module { single { Dispatchers.IO } }

val repositoryModule = module {
  single<NotesRepository> { NotesRepositoryImpl(get(), get()) }
}

Here, you have a repositoryModule that provides an instance of your NotesRepository. The NotesRepositoryImpl class requires two parameters, ioDispatcher and notesDao. You get these parameters from the Koin container using the get() function. Additionally, you have a dispatcherModule. This module provides an instance of the IO coroutine dispatcher. You’ll use the dispatcher to run the database operations on a background thread.

Continuing in Modules.kt, add these two new module declarations to your appModules list. appModules should now look like this:

val appModules = listOf(
  dataStoreModule,
  viewModelModule,
  notesFileManagerModule,
  roomDatabaseModule,
  repositoryModule,
  dispatcherModule
)

Now, you need to update your MainViewModel class to use your newly created NotesRepository. Open the MainViewModel.kt file and update the class as shown below:

class MainViewModel(
  private val dataStoreManager: DataStoreManager,
  private val internalNotesFileManager: InternalNotesFileManager,
  private val externalNotesFileManager: ExternalNotesFileManager,
  private val notesRepository: NotesRepository
): ViewModel() {
  // Rest of the code
}

In the code above, you’ve added a new parameter notesRepository to the MainViewModel class. This parameter is an instance of the NotesRepository interface that has the CRUD operations from your DAO.

Next, you’ll update your handleCreateNoteEvents() function to handle saving the notes to Room database when the user selects Room Database as their storage option. Replace the else block and the // TODO: Implement other note locations TODO with the following code:

"Room Database" -> {
  notesRepository.saveNote(noteEntity)
}

You’ve added a new branch to the when expression that checks if the user selected Room Database as their storage option. If the user selects Room Database, you call the saveNote function on the notesRepository object to save the note to the database.

Lastly, update the fetchNotes() function to get the notes from the Room database too. Replace the code in the fetchNotes() function with the following code:

private fun fetchNotes() {
  viewModelScope.launch {
    notesRepository.getNotes().collect { notes ->
      _notes.update {
        notes + externalNotesFileManager.readTextFile() + internalNotesFileManager.readTextFile()
      }
    }
  }
}

The function now:

  • Launches a coroutine in the viewModelScope. Inside the coroutine, you call the getNotes function from notesRepository. The getNotes function returns a Flow of List<NoteEntity>. You call the collect function on the Flow to get the list of notes from the database.
  • Inside the collect function, you update the _notes state with the notes from the database, internal storage, and external storage. The function now returns a combined list of all notes from the database, internal storage, and external storage.

Head over to the Modules.kt file and add another get() parameter function in the MainViewModel to provide an instance of your NotesRepository:

  viewModel { MainViewModel(get(), get(), get(), get()) }

Build and run your app. You should see the notes that you just created earlier. Tap Create Note to navigate to the Create Note screen. Fill in the form with the title and description, select a priority, and select Room Database as the note location. Tap Create Note to create the note, which saves the note to Room Database and navigates back to the home screen. You should see the note you created displayed on the home screen. You’ll now see all the notes from the database. These include internal storage and external storage. The notes are displayed on the home screen but with different icons. The icons indicate their storage location.

See forum comments
Cinema mode Download course materials from Github
Previous: Instruction Next: Demo: Update & Delete Notes from Room Database