Извлечение одного значения из базы данных Room


Введение

  • Эта серия не будет посвящена базе данных Room для Android. Все, что я найду интересного в базе данных Room, я выложу здесь.

Youtube версия

  • ЗДЕСЬ

Код на GitHub

  • ЗДЕСЬ

Прежде чем начать

  • Для того чтобы это руководство было полезным для вас, пожалуйста, убедитесь, что вы следовали руководству ЗДЕСЬ, или, по крайней мере, у вас есть база данных, запущенная в вашем приложении для android.

Начало работы

  • Итак, в этом руководстве мы рассмотрим, как получить одно значение из базы данных Room и отобразить его в пользовательском интерфейсе. Я хочу подчеркнуть еще раз: если у вас нет базы данных, пожалуйста, следуйте официальному коду лаборатории Room, ЗДЕСЬ.

DAO

  • Начнем с объекта доступа к данным (DAO), все мы знаем, что это область, где мы задаем SQL-запросы и связываем их с вызовами методов. Поскольку мы хотим получить одну полную строку таблицы, мы делаем такой запрос:
@Query("SELECT * FROM calf WHERE calf.id==:calfId")
     suspend fun findCalf(calfId:Long):Calf
Войти в полноэкранный режим Выйти из полноэкранного режима
  • Код довольно прост, единственное, на что стоит обратить внимание, это ключевое слово suspend. Но прежде чем мы сможем поговорить об этом ключевом слове, нам нужно поговорить о корутинах.

Coroutines

  • Как сказано в документации: coroutine - это экземпляр приостанавливаемого вычисления, что означает, что код внутри coroutines выполняется асинхронно. Так являются ли корутины версией Threads в Kotlin? Нет, это не так. Концептуально корутины похожи на потоки тем, что они берут блок кода и выполняют его асинхронно. Но на самом деле корутины выполняются поверх потоков и даже не привязаны к конкретному потоку. Они могут начинаться в одном потоке и заканчиваться в другом. Хорошее визуальное представление корутины можно найти ЗДЕСЬ.
  • Я также хочу отметить, что код внутри coroutine выполняется последовательно (это будет важно позже).

Приостановка функций

  • Теперь, когда у нас есть базовое понимание того, что coroutine — это часть асинхронного кода, мы можем поговорить о ключевом слове suspend. Первое, что следует отметить о функции suspend, это то, что она может быть вызвана только из другой функции suspend или внутри coroutine. Основная идея этого модификатора функций заключается в том, чтобы позволить нам программировать более декларативно и уйти от типичного callback hell. Хотя, с технической точки зрения, компилятор Kotlin превратит все функции приостановки в оптимизированные обратные вызовы для нас.
  • Когда мы видим функцию suspend, эта функция должна быть вызвана из другой приостановленной функции или корутины.

Репозиторий

  • Следующий уровень в этой архитектуре — это уровень хранилища. Хотя он и не является необходимым, его наличие считается лучшей практикой. Его основная задача — обеспечить чистый API для доступа к данным для остальной части приложения. Код в слое хранилища будет выглядеть следующим образом:
suspend fun findCalf(calfId:Long):Calf{
        return calfDao.findCalf(calfId)
    }

Вход в полноэкранный режим Выход из полноэкранного режима
  • В этом коде нет ничего такого, чего бы мы не видели раньше. Единственное, что следует отметить, это то, что мы вызываем метод calfDao.findCalf(calfId), который, как мы знаем, является приостанавливающей функцией, что означает, что findCalf() также должна быть приостанавливающей функцией.

ViewModel

  • Здесь все начинает становиться немного сложнее. Например, наш метод выглядит следующим образом:
suspend fun findCalf(calfId:Long):Calf{
        val deferred:Deferred<Calf> = viewModelScope.async {
            repository.findCalf(calfId)
        }
        return deferred.await()
    }

Войти в полноэкранный режим Выйти из полноэкранного режима
  • Здесь много странных и причудливых слов, но давайте начнем с async{...}. async называется построителем корутины, помните, я говорил, что функции приостановки должны вызываться внутри корутины или функции приостановки, так вот async{} создает для нас корутину. Теперь каждая coroutine должна иметь coroutine scope, которая, по сути, является временем жизни coroutine. Для нашего кода область видимости корутины — это viewModelScope, которая является специфической областью видимости, предоставленной нам Android. viewModelScope.async{...} означает, что код внутри этой coroutine привязан к данной ViewModel, и если ViewModel будет закрыта, то и coroutine тоже.

  • Я уверен, что вы, вероятно, используете launch{} вместо async{}. Основная разница между ними заключается в том, что async возвращает то, что называется объектом Deferred. Этот тип объекта похож на Promise из Future. По сути, это объект, который вернется в какой-то момент в будущем. В нашем коде он возвращает Deferred<Calf>, который является отложенным объектом, содержащим объект Calf. Хорошо, но наша функция возвращает теленка, так как же нам получить нашего теленка вне отложенного объекта? Мы сделаем это, вызвав метод await() на отложенном объекте, который заставит функцию приостановиться, пока она ожидает возвращения метода. Это означает, что данная функция должна быть функцией suspend, что означает, что эта функция должна быть вызвана из coroutine или другой функции приостановки.

Подключение к пользовательскому интерфейсу

  • Это еще одна часть статьи, которая может стать немного странной, поэтому слушайте внимательно!
  • Мы начинаем внутри метода onViewCreated() нашего класса Fragment и знаем, что нам нужно создать корутину для вызова нашего метода findCalf() на ViewHolder, мы делаем это следующим образом:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

CoroutineScope(Main).launch {

  foundCalf = calfViewModel.findCalf(calfId)

        }


Вход в полноэкранный режим Выйти из полноэкранного режима
  • Самое важное, на что следует обратить внимание, это CoroutineScope(Main). Именно так мы можем взаимодействовать с пользовательским интерфейсом, Android не позволяет нам взаимодействовать с пользовательским интерфейсом, если мы находимся в другом потоке, кроме основного. Поэтому CoroutineScope(Main) переключает область видимости нашей корутины на основной поток. Теперь мы можем использовать объект Calf, хранящийся внутри foundCalf, для обновления нашего пользовательского интерфейса.

Заключение

  • Спасибо, что нашли время, чтобы прочитать эту статью в моем блоге. Если у вас возникли вопросы или проблемы, пожалуйста, комментируйте их ниже или свяжитесь со мной в Twitter.

Оцените статью
devanswers.ru
Добавить комментарий