1. Обзор
В предыдущем практическом занятии вы использовали статические ярлыки для реализации часто используемых встроенных интентов (BII) в примере приложения. Разработчики Android используют действия приложений (App Actions) для расширения функциональности приложения для работы с Google Ассистентом.
Статические ярлыки поставляются вместе с приложением и могут быть обновлены только при выпуске новых версий приложения. Включение голосовых функций для динамических элементов в приложении, таких как пользовательский контент, достигается с помощью динамических ярлыков . Приложения отправляют динамические ярлыки после того, как пользователи выполняют соответствующие действия, например, создают новую заметку в приложении для отслеживания задач. С помощью App Actions вы можете включить эти голосовые ярлыки, привязав их к BII, что позволит пользователям получать доступ к своему контенту из Ассистента, произнося, например: «Привет, Google, открой мой список покупок в ExampleApp».

Рисунок 1. Три последовательных экрана, отображающие созданную пользователем задачу и запуск Google Assistant динамического ярлыка для этого элемента задачи.
Что вы построите
В этом практическом занятии вы включите динамические голосовые команды в примере приложения для Android, позволяющего пользователям просить Ассистента открывать созданные ими в приложении элементы списка задач. Для этого используются архитектурные шаблоны Android, а именно шаблоны ` repository` , `service locator` и `ViewModel` .
Предварительные требования
Данный практический урок основан на концепциях App Actions, рассмотренных в предыдущем уроке , в частности, на BII и статических ярлыках. Если вы новичок в App Actions, мы рекомендуем пройти предыдущий урок, прежде чем продолжить.
Кроме того, перед продолжением убедитесь, что ваша среда разработки имеет следующую конфигурацию:
- Терминал для выполнения команд оболочки при установленном Git.
- Последняя стабильная версия Android Studio .
- Физическое или виртуальное устройство Android с доступом в Интернет.
- Учетная запись Google, которая используется для входа в Android Studio, приложение Google и приложение Google Assistant.
2. Разберитесь, как это работает.
Для включения динамического ярлыка для голосового доступа необходимо выполнить следующие шаги:
- Привязка динамического ярлыка к подходящему BII.
- Чтобы Google Ассистент мог интегрировать ярлыки, необходимо добавить библиотеку интеграции Google Shortcuts .
- Нажатие ярлыка всякий раз, когда пользователь выполняет соответствующее задание в приложении.
Сочетания клавиш
Для того чтобы динамический ярлык был доступен из Ассистента, его необходимо привязать к соответствующему BII. Когда активируется BII с ярлыком, Ассистент сопоставляет параметры запроса пользователя с ключевыми словами, определенными в привязанном ярлыке. Например:
- Быстрая команда, привязанная к BII
GET_THINGпозволит пользователям запрашивать определенный контент внутри приложения непосредственно у Ассистента. * "Привет, Google, открой мой список покупок в ExampleApp." - Ярлык, привязанный к BII
START_EXERCISEпозволит пользователям просматривать свои тренировочные сессии. * "Привет, Google, попроси ExampleApp начать мою обычную тренировку."
Полный список встроенных интентов (BII) по категориям см. в справочнике по встроенным интентам .
Предоставление ярлыков для доступа к Ассистенту.
После привязки ярлыков к BII следующим шагом будет включение возможности обработки этих ярлыков Ассистентом путем добавления библиотеки интеграции Google Shortcuts в ваш проект. Благодаря этой библиотеке Ассистент будет знать о каждом ярлыке, созданном вашим приложением, что позволит пользователям запускать эти ярлыки, используя ключевую фразу ярлыка в Ассистенте.
3. Подготовьте среду разработки.
В этом практическом занятии используется пример приложения-списка дел, разработанного для Android. С помощью этого приложения пользователи могут добавлять элементы в списки, искать элементы списка задач по категориям и фильтровать задачи по статусу выполнения. Скачайте и подготовьте пример приложения, выполнив это задание.
Загрузите базовые файлы.
Выполните следующую команду, чтобы клонировать репозиторий GitHub с примером приложения:
git clone https://github.com/actions-on-google/app-actions-dynamic-shortcuts.git
После клонирования репозитория выполните следующие действия, чтобы открыть его в Android Studio:
- В диалоговом окне «Добро пожаловать в Android Studio» нажмите «Импорт проекта» .
- Выберите папку, куда вы клонировали репозиторий.
В качестве альтернативы, вы можете просмотреть версию тестового приложения, представляющую собой завершенное выполнение задания, клонировав ветку codelab-complete из соответствующего репозитория Github:
git clone https://github.com/actions-on-google/app-actions-dynamic-shortcuts.git --branch codelab-complete
Обновите идентификатор приложения Android.
Обновление идентификатора приложения позволяет однозначно идентифицировать приложение на вашем тестовом устройстве и избежать ошибки «Дублирующееся имя пакета», если приложение загружено в Play Console. Чтобы обновить идентификатор приложения, откройте файл app/build.gradle :
android {
...
defaultConfig {
applicationId "com.MYUNIQUENAME.android.fitactions"
...
}
}
Замените "MYUNIQUENAME" в поле applicationId на уникальное для вас имя.
Добавить зависимости API для ярлыков
Добавьте следующие библиотеки Jetpack в файл ресурсов app/build.gradle :
app/build.gradle
dependencies {
...
// Shortcuts library
implementation "androidx.core:core:1.6.0"
implementation 'androidx.core:core-google-shortcuts:1.0.1'
...
}
Протестируйте приложение на своем устройстве.
Прежде чем вносить дальнейшие изменения в приложение, полезно ознакомиться с возможностями демонстрационного приложения. Чтобы запустить приложение на эмуляторе, выполните следующие действия:
- В Android Studio выберите Run > Run app или нажмите Run.
на панели инструментов. - В диалоговом окне «Выбор целевого устройства развертывания» выберите устройство и нажмите «ОК» . Рекомендуемая версия ОС — Android 10 (уровень API 30) или выше, хотя App Actions работает на устройствах, начиная с Android 5 (уровень API 21) .
- Нажмите и удерживайте кнопку «Домой», чтобы настроить Ассистента и убедиться в его работоспособности. Вам потребуется войти в Ассистента на вашем устройстве, если вы еще этого не сделали.
Для получения дополнительной информации о виртуальных устройствах Android см. раздел «Создание и управление виртуальными устройствами» .
Кратко изучите приложение, чтобы увидеть, что оно может делать. Нажатие на значок «Плюс» создает новый элемент задачи, а пункты меню в правом верхнем углу позволяют искать и фильтровать элементы задач по статусу выполнения.
4. Создайте класс-репозиторий ярлыков.
В нашем примере приложения несколько классов будут вызывать API ShortcutManagerCompat для добавления и управления динамическими сочетаниями клавиш. Чтобы уменьшить избыточность кода, вам потребуется реализовать репозиторий, который позволит классам вашего проекта легко управлять динамическими сочетаниями клавиш.
Шаблон проектирования «репозиторий» предоставляет чистый API для управления ярлыками. Преимущество репозитория заключается в том, что детали базового API единообразно абстрагированы за минимальным API. Реализуйте репозиторий, выполнив следующие шаги:
- Создайте класс
ShortcutsRepositoryдля абстрагирования APIShortcutManagerCompat. - Добавьте методы
ShortcutsRepositoryв локатор служб приложения. - Зарегистрируйте сервис
ShortcutRepositoryв главном приложении.
Создайте репозиторий
Создайте новый класс Kotlin с именем ShortcutsRepository в пакете com.example.android.architecture.blueprints.todoapp.data.source . Этот пакет находится в папке app/src/main/java . Вы будете использовать этот класс для реализации интерфейса, предоставляющего минимальный набор методов, охватывающих наш пример из практического задания.

Рисунок 2. Окно «Файлы проекта Android Studio», отображающее расположение класса ShortcutsRepository.
Вставьте следующий код в новый класс:
package com.example.android.architecture.blueprints.todoapp.data.source
import android.content.Context
import android.content.Intent
import androidx.annotation.WorkerThread
import androidx.core.content.pm.ShortcutInfoCompat
import androidx.core.content.pm.ShortcutManagerCompat
import com.example.android.architecture.blueprints.todoapp.data.Task
import com.example.android.architecture.blueprints.todoapp.tasks.TasksActivity
private const val GET_THING_KEY = "q"
/**
* ShortcutsRepository provides an interface for managing dynamic shortcuts.
*/
class ShortcutsRepository(val context: Context) {
private val appContext = context.applicationContext
/**
* Pushes a dynamic shortcut. The task ID is used as the shortcut ID.
* The task's title and description are used as shortcut's short and long labels.
* The resulting shortcut corresponds to the GET_THING capability with task's
* title used as BII's "name" argument.
*
* @param task Task object for which to create a shortcut.
*/
@WorkerThread
fun pushShortcut(task: Task) {
// TODO
}
private fun createShortcutCompat(task: Task): ShortcutInfoCompat {
//...
}
/**
* Updates a dynamic shortcut for the provided task. If the shortcut
* associated with this task doesn't exist, this method throws an error.
* This operation may take a few seconds to complete.
*
* @param tasks list of tasks to update.
*/
@WorkerThread
fun updateShortcuts(tasks: List<Task>) {
//...
}
/**
* Removes shortcuts if IDs are known.
*
* @param ids list of shortcut IDs
*/
@WorkerThread
fun removeShortcutsById(ids: List<String>) {
//...
}
/**
* Removes shortcuts associated with the tasks.
*
* @param tasks list of tasks to remove.
*/
@WorkerThread
fun removeShortcuts(tasks: List<Task>) {
//...
}
}
Далее обновите метод pushShortcut , чтобы он вызывал API ShortcutManagerCompat . Обновите класс ShortcutsRepository , добавив следующий код:
ShortcutsRepository.kt
/**
* Pushes a dynamic shortcut for the task. The task's ID is used as a shortcut
* ID. The task's title and description are used as shortcut's short and long
* labels. The created shortcut corresponds to GET_THING capability with task's
* title used as BII's "name" argument.
*
* @param task Task object for which to create a shortcut.
*/
@WorkerThread
fun pushShortcut(task: Task) {
ShortcutManagerCompat.pushDynamicShortcut(appContext, createShortcutCompat(task))
}
В приведенном выше примере кода мы передали API appContext . Это свойство класса, содержащее объект ` ApplicationContext` . Важно использовать `ApplicationContext` (в отличие от ` ActivityContext` ), чтобы избежать утечек памяти, поскольку контекст может сохраняться дольше, чем жизненный цикл хост-активности.
Кроме того, API требует передачи объекта ShortcutInfoCompat для объекта Task. В приведенном выше примере кода мы делаем это, вызывая приватный метод createShortcutCompat , который мы обновим, чтобы он создавал и возвращал объект ShortcutInfoCompat . Для этого обновите заглушку createShortcutCompat следующим кодом:
ShortcutsRepository.kt
private fun createShortcutCompat(task: Task): ShortcutInfoCompat {
val intent = Intent(appContext, TasksActivity::class.java)
intent.action = Intent.ACTION_VIEW
// Filtering is set based on currentTitle.
intent.putExtra(GET_THING_KEY, task.title)
// A unique ID is required to avoid overwriting an existing shortcut.
return ShortcutInfoCompat.Builder(appContext, task.id)
.setShortLabel(task.title)
.setLongLabel(task.title)
// Call addCapabilityBinding() to link this shortcut to a BII. Enables user to invoke a shortcut using its title in Assistant.
.addCapabilityBinding(
"actions.intent.GET_THING", "thing.name", listOf(task.title))
.setIntent(intent)
.setLongLived(false)
.build()
}
Оставшиеся заглушки функций в этом классе отвечают за обновление и удаление динамических сочетаний клавиш. Чтобы включить эти функции, обновите их следующим кодом:
ShortcutsRepository.kt
/**
* Updates a Dynamic Shortcut for the task. If the shortcut associated with this task
* doesn't exist, throws an error. This operation may take a few seconds to complete.
*
* @param tasks list of tasks to update.
*/
@WorkerThread
fun updateShortcuts(tasks: List<Task>) {
val scs = tasks.map { createShortcutCompat(it) }
ShortcutManagerCompat.updateShortcuts(appContext, scs)
}
/**
* Removes shortcuts if IDs are known.
* @param ids list of shortcut IDs
*/
@WorkerThread
fun removeShortcutsById(ids: List<String>) {
ShortcutManagerCompat.removeDynamicShortcuts(appContext, ids)
}
/**
* Removes shortcuts associated with the tasks.
*
* @param tasks list of tasks to remove.
*/
@WorkerThread
fun removeShortcuts(tasks: List<Task>) {
ShortcutManagerCompat.removeDynamicShortcuts (appContext,
tasks.map { it.id })
}
Добавить класс в локатор услуг
После создания класса ShortcutsRepository следующим шагом является предоставление доступа к созданным экземплярам этого класса остальной части приложения. Это приложение управляет зависимостями классов, реализуя шаблон ServiceLocator . Откройте класс ServiceLocator с помощью браузера классов в Android Studio, перейдя в Navigate > Class и введя "ServiceLocator". Щелкните по полученному файлу Kotlin, чтобы открыть его в вашей IDE.
В верхней части файла ServiceLocator.kt вставьте следующий код для импорта пакетов ShortcutsRepository и SuppressLint :
ServiceLocator.kt
package com.example.android.architecture.blueprints.todoapp
// ...Other import statements
import com.example.android.architecture.blueprints.todoapp.data.source.ShortcutsRepository
import android.annotation.SuppressLint
Добавьте члены и методы сервиса ShortcutRepository , вставив следующий код в тело файла ServiceLocator.kt :
ServiceLocator.kt
object ServiceLocator {
// ...
// Only the code immediately below this comment needs to be copied and pasted
// into the body of ServiceLocator.kt:
@SuppressLint("StaticFieldLeak")
@Volatile
var shortcutsRepository: ShortcutsRepository? = null
private fun createShortcutsRepository(context: Context): ShortcutsRepository {
val newRepo = ShortcutsRepository(context.applicationContext)
shortcutsRepository = newRepo
return newRepo
}
fun provideShortcutsRepository(context: Context): ShortcutsRepository {
synchronized(this) {
return shortcutsRepository ?: shortcutsRepository ?: createShortcutsRepository(context)
}
}
}
Зарегистрируйте службу ярлыков
Последний шаг — регистрация нового сервиса ShortcutsRepository в приложении. В Android Studio откройте файл TodoApplication.kt и скопируйте следующий код в начало файла:
TodoApplication.kt
package com.example.android.architecture.blueprints.todoapp
/// ... Other import statements
import com.example.android.architecture.blueprints.todoapp.data.source.ShortcutsRepository
Далее зарегистрируйте сервис, добавив следующий код в тело класса:
TodoApplication.kt
//...
class TodoApplication : Application() {
//...
val shortcutsRepository: ShortcutsRepository
get() = ServiceLocator.provideShortcutsRepository(this)
//...
}
Соберите приложение и убедитесь, что оно продолжает работать.
5. Создайте новый ярлык.
После создания службы ярлыков вы готовы начать их отправку. Поскольку пользователи создают контент (элементы задач) в этом приложении и ожидают возможности вернуться к нему позже, мы будем активировать голосовой доступ к этому контенту, отправляя динамический ярлык, привязанный к BII GET_THING , каждый раз, когда пользователь создает новую задачу. Это позволит Ассистенту запускать пользователей непосредственно к запрошенному элементу задачи, когда они активируют BII, задавая, например: « Привет, Google, открой мой список покупок в SampleApp».
Чтобы включить эту функцию в демонстрационном приложении, выполните следующие действия:
- Импорт сервиса
ShortcutsRepositoryв классAddEditTaskViewModel, отвечающий за управление объектами списка задач. - Нажатие динамического ярлыка при создании пользователем новой задачи.
Импортировать репозиторий ярлыков
Сначала нам нужно сделать сервис ShortcutsRepository доступным для AddEditTaskViewModel . Для этого импортируйте сервис в ViewModelFactory , класс-фабрику, который приложение использует для создания экземпляров объектов ViewModel , включая AddEditTaskViewModel .
Откройте браузер классов в Android Studio, перейдя в меню «Навигация» > «Классы» и введя «ViewModelFactory». Щелкните по появившемуся файлу Kotlin, чтобы открыть его в вашей IDE.
В верхней части файла ViewModelFactory.kt вставьте следующий код для импорта пакетов ShortcutsRepository и SuppressLint :
ViewModelFactory.kt
package com.example.android.architecture.blueprints.todoapp
// ...Other import statements
import com.example.android.architecture.blueprints.todoapp.data.source.ShortcutsRepository
Далее замените содержимое ViewModelFactory следующим кодом:
ViewModelFactory.kt
/**
* Factory for all ViewModels.
*/
@Suppress("UNCHECKED_CAST")
class ViewModelFactory constructor(
private val tasksRepository: TasksRepository,
private val shortcutsRepository: ShortcutsRepository,
owner: SavedStateRegistryOwner,
defaultArgs: Bundle? = null
) : AbstractSavedStateViewModelFactory(owner, defaultArgs) {
override fun <T : ViewModel> create(
key: String,
modelClass: Class<T>,
handle: SavedStateHandle
) = with(modelClass) {
when {
isAssignableFrom(StatisticsViewModel::class.java) ->
StatisticsViewModel(tasksRepository)
isAssignableFrom(TaskDetailViewModel::class.java) ->
TaskDetailViewModel(tasksRepository)
isAssignableFrom(AddEditTaskViewModel::class.java) ->
AddEditTaskViewModel(tasksRepository, shortcutsRepository)
isAssignableFrom(TasksViewModel::class.java) ->
TasksViewModel(tasksRepository, handle)
else ->
throw IllegalArgumentException("Unknown ViewModel class: ${modelClass.name}")
}
} as T
}
Завершите изменения в ViewModelFactory , поднявшись на один уровень выше, и передайте ShortcutsRepository в конструктор фабрики. Откройте файловый менеджер Android Studio, перейдя в меню «Навигация» > «Файл» и набрав «FragmentExt.kt». Щелкните по полученному файлу Kotlin, расположенному в пакете util , чтобы открыть его в вашей IDE.
Замените содержимое файла FragmentExt.kt следующим кодом:
fun Fragment.getViewModelFactory(): ViewModelFactory {
val taskRepository = (requireContext().applicationContext as TodoApplication).taskRepository
val shortcutsRepository = (requireContext().applicationContext as TodoApplication).shortcutsRepository
return ViewModelFactory(taskRepository, shortcutsRepository, this)
}
Нажмите на ярлык
Благодаря доступу к классу абстракции ShortcutsRepository для классов ViewModel в примере приложения, вы можете обновить класс ViewModel AddEditTaskViewModel , отвечающий за создание заметок, чтобы каждый раз при создании пользователем новой заметки автоматически добавлялась динамическая комбинация клавиш.
В Android Studio откройте браузер классов и введите "AddEditTaskViewModel". Щелкните по появившемуся файлу Kotlin, чтобы открыть его в вашей IDE.
Сначала добавьте пакет ShortcutsRepository к этому классу, используя следующую инструкцию импорта:
package com.example.android.architecture.blueprints.todoapp.addedittask
//Other import statements
import com.example.android.architecture.blueprints.todoapp.data.source.ShortcutsRepository
Далее добавьте свойство класса shortcutsRepository , обновив конструктор класса следующим кодом:
AddEditTaskViewModel.kt
//...
/**
* ViewModel for the Add/Edit screen.
*/
class AddEditTaskViewModel(
private val tasksRepository: TasksRepository,
private val shortcutsRepository: ShortcutsRepository
) : ViewModel() {
//...
После добавления класса ShortcutsRepository создайте новую функцию pushShortcut() для вызова этого класса. Вставьте следующую приватную функцию в тело класса AddEditTaskViewModel :
AddEditTaskViewModel.kt
//...
private fun pushShortcut(newTask: Task) = viewModelScope.launch {
shortcutsRepository.pushShortcut(newTask)
}
Наконец, при каждом создании задачи добавляйте новый динамический ярлык. Замените содержимое функции saveTask() следующим кодом:
AddEditTaskViewModel.kt
fun saveTask() {
val currentTitle = title.value
val currentDescription = description.value
if (currentTitle == null || currentDescription == null) {
_snackbarText.value = Event(R.string.empty_task_message)
return
}
if (Task(currentTitle, currentDescription).isEmpty) {
_snackbarText.value = Event(R.string.empty_task_message)
return
}
val currentTaskId = taskId
if (isNewTask || currentTaskId == null) {
val task = Task(currentTitle, currentDescription)
createTask(task)
pushShortcut(task)
} else {
val task = Task(currentTitle, currentDescription, taskCompleted, currentTaskId)
updateTask(task)
}
}
Протестируйте свой код
Наконец-то мы готовы протестировать наш код! На этом шаге вы активируете динамический ярлык с поддержкой голосового управления и проверяете его работу с помощью приложения Google Ассистент.
Создать предварительный просмотр
Создание предварительного просмотра с помощью плагина Google Assistant позволяет отображать ваши динамические ярлыки в Ассистенте на тестовом устройстве.
Установите тестовый плагин
Если у вас еще нет плагина Google Assistant, установите его, выполнив следующие действия в Android Studio:
- Перейдите в меню **Файл > Настройки** (Android Studio > Настройки в MacOS).
- В разделе «Плагины» перейдите в Marketplace и найдите «Google Assistant».
- Если вы не можете найти плагин на Marketplace, загрузите его вручную и следуйте инструкциям по установке плагина с диска .
- Установите инструмент и перезапустите Android Studio.
Создать предварительный просмотр
Создайте предварительный просмотр, выполнив следующие действия в Android Studio:
- Нажмите «Инструменты» > «Google Ассистент» > « Инструмент проверки действий приложения ».
- В поле «Название приложения » укажите, например, «Список дел».
- Нажмите «Создать предварительный просмотр» . При необходимости ознакомьтесь с политикой и условиями использования App Actions и примите их.

Рисунок 3. Панель предварительного просмотра при создании инструмента тестирования действий приложения.
В процессе тестирования динамические ярлыки, которые вы добавляете в Ассистент, будут отображаться в Ассистенте в порядке убывания имени приложения , указанного вами для предварительного просмотра.
Нажмите и проверьте ярлык
Перезапустите демонстрационное приложение на тестовом устройстве и выполните следующие действия:
- Создайте новую задачу с заголовком «Начало практического занятия».
- Откройте приложение Google Ассистент и произнесите или наберите: «Мои ярлыки».
- Нажмите вкладку «Исследовать» . Вы должны увидеть пример ярлыка.
- Нажмите на ярлык, чтобы вызвать его. Вы увидите, как приложение запустится, и имя ярлыка будет автоматически заполнено в поле фильтра, что упростит поиск нужного элемента задачи.
6. (Необязательно) Обновить и удалить ярлык
Помимо добавления новых динамических ярлыков во время выполнения, ваше приложение может обновлять их, отражая текущее состояние пользовательского контента и настроек. Рекомендуется обновлять существующие ярлыки всякий раз, когда пользователь изменяет целевой элемент, например, переименовывает задачу в нашем примере приложения. Также следует удалять соответствующий ярлык всякий раз, когда удаляется целевой ресурс, чтобы избежать отображения неработающих ярлыков пользователю.
Обновить ярлык
Измените AddEditTaskViewModel , чтобы динамический ярлык обновлялся всякий раз, когда пользователь изменяет сведения об элементе задачи. Сначала обновите тело класса, добавив следующий код, чтобы создать функцию обновления, использующую наш класс репозитория:
AddEditTaskViewModel.kt
private fun updateShortcut(newTask: Task) = viewModelScope.launch {
shortcutsRepository.updateShortcuts(listOf(newTask))
}
Далее, измените функцию saveTask() таким образом, чтобы она вызывала наш новый метод всякий раз, когда обновляется существующая задача.
AddEditTaskViewModel.kt
// Called when clicking on fab.
fun saveTask() {
// ...
// Note: the shortcuts are created/updated in a worker thread.
if (isNewTask || currentTaskId == null) {
//...
} else {
//...
updateShortcut(task)
}
}
Проверьте свой код, перезапустив приложение и выполнив следующие шаги:
- Переименуйте заголовок существующего элемента задачи в «Завершить практическую работу».
- Чтобы открыть Google Ассистент, произнесите: «Привет, Google, мои ярлыки».
- Нажмите вкладку «Исследовать» . Вы должны увидеть обновленное краткое название вашего тестового ярлыка.
Удалить ярлык
В нашем примере приложения ярлыки должны удаляться всякий раз, когда пользователь удаляет задачу. В примере приложения логика удаления задач находится в классе TaskDetailViewModel . Прежде чем обновлять этот класс, нам необходимо снова обновить ViewModelFactory , чтобы передать shortcutsRepository в TaskDetailViewModel .
Откройте ViewModelFactory и замените содержимое его метода конструктора следующим кодом:
//...
class ViewModelFactory constructor(
private val tasksRepository: TasksRepository,
private val shortcutsRepository: ShortcutsRepository,
owner: SavedStateRegistryOwner,
defaultArgs: Bundle? = null
) : AbstractSavedStateViewModelFactory(owner, defaultArgs) {
override fun <T : ViewModel> create(
key: String,
modelClass: Class<T>,
handle: SavedStateHandle
) = with(modelClass) {
when {
isAssignableFrom(StatisticsViewModel::class.java) ->
StatisticsViewModel(tasksRepository)
isAssignableFrom(TaskDetailViewModel::class.java) ->
TaskDetailViewModel(tasksRepository, shortcutsRepository)
isAssignableFrom(AddEditTaskViewModel::class.java) ->
AddEditTaskViewModel(tasksRepository, shortcutsRepository)
isAssignableFrom(TasksViewModel::class.java) ->
TasksViewModel(tasksRepository, handle)
else ->
throw IllegalArgumentException("Unknown ViewModel class: ${modelClass.name}")
}
} as T
}
Далее откройте TaskDetailViewModel . Импортируйте модуль ShortcutsRepository и объявите для него переменную экземпляра, используя следующий код:
TaskDetailViewModel.kt
package com.example.android.architecture.blueprints.todoapp.taskdetail
...
import com.example.android.architecture.blueprints.todoapp.data.source.ShortcutsRepository
/**
* ViewModel for the Details screen.
*/
class TaskDetailViewModel(
//...
private val shortcutsRepository: ShortcutsRepository
) : ViewModel() {
...
}
Наконец, измените функцию deleteTask() таким образом, чтобы она вызывала shortcutsRepository для удаления ярлыка на основе его ID всякий раз, когда удаляется задача с соответствующим taskId :
TaskDetailViewModel.kt
fun deleteTask() = viewModelScope.launch {
_taskId.value?.let {
//...
shortcutsRepository.removeShortcutsById(listOf(it))
}
}
Чтобы протестировать свой код, перезапустите приложение и выполните следующие действия:
- Удалите свою тестовую задачу.
- Переименуйте заголовок существующего элемента задачи в «Завершить практическую работу».
- Чтобы открыть Google Ассистент, произнесите: «Привет, Google, мои ярлыки».
- Нажмите вкладку «Исследовать» . Убедитесь, что ваш тестовый ярлык больше не отображается.
7. Дальнейшие шаги
Поздравляем! Благодаря вам пользователи нашего демонстрационного приложения могут легко вернуться к созданным ими заметкам, задав Ассистенту, например: «Привет, Google, открой мой список покупок в ExampleApp». Ярлыки способствуют более глубокому вовлечению пользователей, позволяя им легко воспроизводить часто используемые действия в вашем приложении.
Что мы рассмотрели
В этом практическом занятии вы научились:
- Определите сценарии использования динамических ярлыков в приложении.
- Снизьте сложность кода, используя шаблоны проектирования «репозиторий», «внедрение зависимостей» и «локатор сервисов».
- Добавьте динамические ярлыки с поддержкой голосового управления к контенту приложения, созданному пользователями.
- Обновите и удалите существующие ярлыки.
Что дальше?
Отсюда вы можете попробовать внести дальнейшие улучшения в ваше приложение «Список задач». Чтобы посмотреть готовый проект, перейдите в репозиторий –codelab-complete на GitHub.
Вот несколько рекомендаций для дальнейшего изучения возможностей расширения функциональности этого приложения с помощью App Actions:
- Ознакомьтесь с примером списка задач с использованием Google Analytics для Firebase, чтобы узнать, как отслеживать эффективность действий вашего приложения.
- Чтобы узнать больше о способах расширения функциональности ваших приложений для Google Ассистента, посетите раздел «Справочник по встроенным интентам в App Actions».
Чтобы продолжить работу с Actions on Google, ознакомьтесь с этими ресурсами:
- actions.google.com : Официальный сайт документации по Actions on Google.
- Указатель примеров приложений и кода для изучения возможностей App Actions.
- Действия в репозитории Google GitHub : примеры кода и библиотек.
- r/GoogleAssistantDev : Официальное сообщество Reddit для разработчиков, работающих с Google Assistant.
Подписывайтесь на нас в Twitter @ActionsOnGoogle, чтобы быть в курсе наших последних анонсов, и публикуйте твиты с хэштегом #appActions , чтобы поделиться своими разработками!
Опрос обратной связи
В заключение, пожалуйста, заполните этот опрос , чтобы оставить отзыв о вашем опыте работы с этим практическим занятием.