Save User State

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

Lesson 03: Read & Write Files

Read & Write Files in External Storage

Episode complete

Play next episode

Next

Heads up... You’re accessing parts of this content for free, with some sections shown as obfuscated text.

Heads up... You’re accessing parts of this content for free, with some sections shown as obfuscated text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

Creating External Notes

Continuing from where we left, reopen the starter project, then build and run your app. You should see the note 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 External Storage as the note location. Tap Create Note to create the note, but your note won’t save to external storage yet. You’ll implement the read and write operations to external storage in the next steps.

import android.content.Context
import android.os.Environment
import com.kodeco.android.devscribe.data.local.NoteEntity
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import java.io.File
import java.io.IOException

class ExternalNotesFileManager(
  private val context: Context
) {
  fun writeTextFile(note: NoteEntity) {
    if (!isExternalStorageWritable()) {
      return
    }
    val directory = File(context.getExternalFilesDir(null), DIRECTORY_NAME)
    if (!directory.exists()) {
      directory.mkdirs()
    }
    val file = File(directory, "${note.title}.txt")
    try {
      file.outputStream().use { outputStream ->
        outputStream.write(Json.encodeToString(note).toByteArray())
      }
    } catch (e: IOException) {
      e.printStackTrace()
    }
  }

  private  fun isExternalStorageWritable(): Boolean =
    Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED

  companion object {
    const val DIRECTORY_NAME = "DevScribeNotesExternal"
  }
}
fun readTextFile(): List<NoteEntity> {
  if (!isExternalStorageReadable()) {
    return emptyList()
  }
  val directory = File(context.getExternalFilesDir(null), DIRECTORY_NAME)
  val noteFiles = directory.listFiles()?.filter { it.isFile && it.name.endsWith(".txt") }
  val notes = mutableListOf<NoteEntity>()
  noteFiles?.forEach { file ->
    try {
      val inputStream = FileInputStream(file)
      val content = inputStream.bufferedReader().use { it.readText() }
      notes.add(
        Json.decodeFromString(content)
      )
    } catch (e: IOException) {
      e.printStackTrace()
    }
  }
  return notes
}
private fun isExternalStorageReadable(): Boolean =
  Environment.getExternalStorageState() in
    setOf(Environment.MEDIA_MOUNTED, Environment.MEDIA_MOUNTED_READ_ONLY)
single { ExternalNotesFileManager(androidContext()) }
val viewModelModule = module {
  viewModel { MainViewModel(get(), get(), get()) }
}
class MainViewModel(
  private val dataStoreManager: DataStoreManager,
  private val internalNotesFileManager: InternalNotesFileManager,
  private val externalNotesFileManager: ExternalNotesFileManager
): ViewModel() {
  // The rest of the code
}
fun handleCreateNoteEvents(event: CreateNoteEvents) {
  when(event) {
    is CreateNoteEvents.TitleChanged -> {
      _createNoteState.update {
        it.copy(title = event.title)
      }
    }
    is CreateNoteEvents.DescriptionChanged -> {
      _createNoteState.update {
        it.copy(description = event.description)
      }
    }
    is CreateNoteEvents.PriorityChanged -> {
      _createNoteState.update {
        it.copy(priority = event.priority)
      }
    }
    is CreateNoteEvents.CreateNote -> {
      if(createNoteState.value.isValid()) {
        viewModelScope.launch {
          val noteEntity = NoteEntity(
            title = createNoteState.value.title ?: "",
            description = createNoteState.value.description ?: "",
            priority = createNoteState.value.priority ?: "",
            timestamp = System.currentTimeMillis(),
            noteLocation = createNoteState.value.noteLocation ?: ""
          )
          when(noteEntity.noteLocation) {
            "Internal Storage" -> {
              internalNotesFileManager.writeTextFile(noteEntity)
            }
            "External Storage" -> {
              externalNotesFileManager.writeTextFile(noteEntity)
            }
            else -> {
              // TODO: Implement other note locations
            }
          }
        }
      }
    }

    is CreateNoteEvents.NoteLocationChanged -> {
      _createNoteState.update {
        it.copy(noteLocation = event.noteLocation)
      }
    }
  }
}
private fun fetchNotes() {
  viewModelScope.launch {
    _notes.update {
      internalNotesFileManager.readTextFile() + externalNotesFileManager.readTextFile()
    }
  }
}
See forum comments
Cinema mode Download course materials from Github
Previous: Read & Write Files in Internal Storage Next: Conclusion