Постоянство файловых операций в фоновом режиме - PullRequest
0 голосов
/ 30 мая 2019

В настоящее время я разрабатываю постоянную библиотеку для Android в Котлине. Сейчас я нахожусь в точке, где я должен обрабатывать файловые операции (чтение, запись и т. Д.), И мне интересно, как лучше всего это сделать? Во-первых, мне не нужно делать это в главном потоке, чтобы заблокировать пользовательский интерфейс. Во-вторых, я должен быть уверен, что все операции выполняются немедленно, и никто не теряется при сбое процесса или перезапуске устройства.

Я посмотрел справочное руководство на сайте разработчика, но теперь я немного растерялся. Поскольку я не хочу запускать службу forground для каждой персистентной операции, похоже, WorkManager - лучшее решение для меня. В документации говорится:

WorkManager предназначен для задач, которые являются отложенными, то есть не требующими немедленного запуска, и которые необходимы для надежной работы, даже если приложение закрывается или устройство перезагружается.

Но вот проблема: моя работа должна быть выполнена немедленно и не зависит от системных событий, поэтому я не уверен, что это лучший способ. Как вы думаете, что является лучшим решением для меня?

1 Ответ

1 голос
/ 30 мая 2019

У вас может быть хранилище, открывающее функции suspend, которые обрабатывают ввод / вывод. Вот TextRepository, который читает и записывает текст из Uri (поскольку он адаптирован из будущего учебника, который поддерживает файлы и значения Storage Access Framework Uri):

class TextRepository(context: Context) {
  private val resolver: ContentResolver = context.contentResolver

  suspend fun read(source: Uri) = withContext(Dispatchers.IO) {
    try {
      resolver.openInputStream(source)?.use { stream ->
        StreamResult.Content(source, stream.readText())
      } ?: throw IllegalStateException("could not open $source")
    } catch (e: FileNotFoundException) {
      StreamResult.Content(source, "")
    } catch (t: Throwable) {
      StreamResult.Error(t)
    }
  }

  suspend fun write(source: Uri, text: String): StreamResult =
    withContext(Dispatchers.IO) {
      try {
        resolver.openOutputStream(source)?.use { stream ->
          stream.writeText(text)
          StreamResult.Content(source, text)
        } ?: throw IllegalStateException("could not open $source")
      } catch (t: Throwable) {
        StreamResult.Error(t)
      }
    }
}

private fun InputStream.readText(charset: Charset = Charsets.UTF_8): String =
  readBytes().toString(charset)

private fun OutputStream.writeText(
  text: String,
  charset: Charset = Charsets.UTF_8
): Unit = write(text.toByteArray(charset))

sealed class StreamResult {
  object Loading : StreamResult()
  data class Content(val source: Uri, val text: String) : StreamResult()
  data class Error(val throwable: Throwable) : StreamResult()
}

В этом случае я использую шаблон загрузки содержимого ошибки (LCE), где функции suspend возвращают StreamResult. StreamResult.Content переносит прочитанный текст или только что написанный текст.

Тогда у вас может быть ViewModel своего рода вызов функций suspend:

class MainMotor(repo: TextRepository) : ViewModel {
  private val _results = MutableLiveData<StreamResult>()
  val results: LiveData<StreamResult> = _results

  fun read(source: Uri) {
    _results.value = StreamResult.Loading

    viewModelScope.launch(Dispatchers.Main) {
      _results.value = repo.read(source)
    }
  }

  fun write(source: Uri, text: String) {
    _results.value = StreamResult.Loading

    viewModelScope.launch(Dispatchers.Main) {
      _results.value = repo.write(source, text)
    }
  }
}

В моем случае я направляю StreamResult без изменений через MutableLiveData для использования пользовательским интерфейсом, следуя шаблону в стиле MVI. На практике ViewModel, вероятно, преобразует результат репо в нечто, более непосредственно используемое пользовательским интерфейсом, и поэтому LiveData будет другого типа, а ViewModel выполняет преобразование.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...