1. Descripción general
En el codelab anterior, configuraste atajos estáticos para implementar intents integrados (BII) de uso general en una app de ejemplo. Los desarrolladores de Android utilizan Acciones en apps para habilitar las funciones de una app con el Asistente de Google.
Los atajos estáticos se empaquetan en una app y solo se pueden actualizar mediante el lanzamiento de versiones nuevas de esa app. La habilitación de una función de voz para elementos dinámicos en una app, como el contenido generado por usuarios, se logra mediante atajos dinámicos. Las apps envían atajos dinámicos después de que los usuarios realizan acciones relevantes, como crear una nota nueva en una app de control de tareas. Con Acciones en apps, puedes vincular esos atajos a un BII a fin de que se habiliten para utilizarse con comandos por voz, lo que permite que los usuarios accedan a su contenido desde el Asistente pronunciando frases como "Hey Google, abre mi lista de compra de comestibles en App de Ejemplo".
Figura 1: Tres pantallas progresivas en las que se muestra cómo el Asistente de Google inicia un atajo dinámico a una tarea creada por el usuario
Qué harás
En este codelab, habilitarás atajos dinámicos que permitirán utilizar comandos por voz en una app de ejemplo de listas de tareas pendientes para Android. De esta manera, los usuarios podrán pedirle al Asistente que abra elementos de una lista de tareas que hayan creado en la app. Para ello, tendrás que utilizar patrones de la arquitectura de Android, específicamente los de repositorio, localizador de servicios y ViewModel.
Requisitos previos
Este codelab se basa en los conceptos de Acciones en apps que se trataron en el codelab anterior, en particular los BII y los atajos estáticos. Si es la primera vez que utilizas Acciones en apps, te recomendamos que completes ese codelab antes de continuar.
Además, asegúrate de que tu entorno de desarrollo tenga la siguiente configuración antes de continuar:
- Una terminal para ejecutar comandos de shell con Git instalado
- La versión estable más reciente de Android Studio
- Un dispositivo Android físico o virtual con acceso a Internet
- Una Cuenta de Google para acceder a Android Studio, la app de Google y la app del Asistente de Google
2. Comprende el funcionamiento
Para habilitar un atajo dinámico que permita el acceso con comandos por voz, se deben seguir estos pasos:
- Vincular un atajo dinámico a un BII adecuado
- Agregar la biblioteca de Google Shortcuts Integration para que el Asistente pueda integrar los atajos
- Enviar un atajo cada vez que un usuario complete una tarea relevante en la app
Vinculación de atajos
Para que un atajo dinámico esté disponible en el Asistente, es necesario vincularlo a un BII relevante. Cuando se activa un BII que incluye un atajo, el Asistente busca coincidencias los parámetros de la solicitud del usuario y las palabras clave definidas en el atajo vinculado. Por ejemplo:
- Un atajo vinculado al BII
GET_THING
podría permitir que los usuarios soliciten contenido específico en la app directamente desde el Asistente. * "Hey Google, abre mi lista de compra de comestibles en App de Ejemplo". - Un atajo vinculado al BII
ORDER_MENU_ITEM
podría permitir que los usuarios repitan pedidos anteriores. * "Hey Google, pide mi comida habitual de App de Ejemplo".
Consulta la referencia de intents integrados para obtener una lista completa de BII por categoría.
Integración de atajos en el Asistente
Después de vincular tus atajos a un BII, el siguiente paso es agregar a tu proyecto la biblioteca de Google Shortcuts Integration con el fin de habilitar el Asistente para que integre esos atajos. Con esta biblioteca configurada, el Asistente detectará los atajos que envíe tu app. De esta manera, los usuarios podrán ejecutar esos atajos en el Asistente utilizando la frase de activación correspondiente a cada uno de ellos.
3. Prepara tu entorno de desarrollo
En este codelab, se utiliza una app de ejemplo de listas de tareas pendientes compilada para Android. Con esa app, los usuarios pueden agregar elementos a listas, buscar elementos en las listas de tareas por categoría y filtrar tareas según el estado de finalización. Completa esta sección para descargar y preparar la app de ejemplo.
Descarga los archivos fundamentales
Ejecuta el siguiente comando para clonar el repositorio de GitHub de la app de ejemplo:
git clone https://github.com/actions-on-google/app-actions-dynamic-shortcuts.git
Una vez que hayas clonado el repositorio, sigue estos pasos para abrirlo en Android Studio:
- En el diálogo Welcome to Android Studio, haz clic en Import project.
- Selecciona la carpeta donde clonaste el repositorio.
También puedes ver una versión de la app de ejemplo que representa el codelab completado. Solo tienes que clonar la rama codelab-complete
del repositorio de GitHub de esa app:
git clone https://github.com/actions-on-google/app-actions-dynamic-shortcuts.git --branch codelab-complete
Actualiza el ID de aplicación para Android
La actualización del ID de aplicación identifica de forma exclusiva la app en tu dispositivo de prueba y evita que se muestre el error "Duplicate package name" si la app se sube a Play Console. Para actualizar el ID de aplicación, abre app/build.gradle
:
android {
...
defaultConfig {
applicationId "com.MYUNIQUENAME.android.fitactions"
...
}
}
Reemplaza "MYUNIQUENAME" en el campo applicationId
por algo que sea único para ti.
Agrega las dependencias de la API de atajos
Agrega las siguientes bibliotecas de Jetpack al archivo del recurso 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'
...
}
Prueba la app en tu dispositivo
Antes de realizar más cambios en la app, es conveniente ejecutarla en tu emulador para tener una idea de lo que puede hacer la app de ejemplo. Para ello, sigue estos pasos:
- En Android Studio, selecciona Run > Run app, o haz clic en Run en la barra de herramientas.
- En el diálogo Select Deployment Target, selecciona un dispositivo y haz clic en OK. La versión de SO recomendada es Android 10 (nivel de API 30) o una posterior, aunque las Acciones en apps también funcionan en dispositivos que tengan hasta la versión Android 5 (nivel de API 21).
- Mantén presionado el botón de inicio para configurar el Asistente y verificar que funcione. Si aún no lo hiciste, tendrás que acceder al Asistente en tu dispositivo.
Para obtener más información sobre los dispositivos virtuales de Android, consulta Cómo crear y administrar dispositivos virtuales.
Explora la app brevemente para ver lo que puede hacer. Si presionas el ícono de signo más, puedes crear una tarea nueva. Además, los elementos de menú en la esquina superior derecha te permiten buscar y filtrar tareas por estado de finalización.
4. Crea una clase de repositorio de atajos
En la app de ejemplo, hay varias clases que llamarán a la API ShortcutManagerCompat
para enviar y administrar atajos dinámicos. A fin de reducir la redundancia en el código, tendrás que implementar un repositorio para habilitar las clases de tu proyecto de forma tal que sea posible administrar los atajos dinámicos fácilmente.
El patrón de diseño del repositorio proporciona una API bien definida para administrar atajos. La ventaja de un repositorio es que abstrae de forma uniforme los detalles de la API subyacente para presentarlos en una API sencilla. Sigue estos pasos para implementar el repositorio:
- Crea una clase
ShortcutsRepository
para abstraer la APIShortcutManagerCompat
. - Agrega métodos de
ShortcutsRepository
al localizador de servicios de la app. - Registra el servicio
ShortcutRepository
en la aplicación principal.
Crea el repositorio
En el paquete com.example.android.architecture.blueprints.todoapp.data.source
, crea una nueva clase en Kotlin llamada ShortcutsRepository
(puedes encontrar el paquete organizado en la carpeta app/src/main/java
). Utilizarás esta clase para implementar una interfaz que proporcione un conjunto reducido de métodos relacionados con el caso de uso de nuestro codelab.
Figura 2: Ventana Project Files de Android Studio que muestra la ubicación de la clase ShortcutsRepository
Pega el siguiente código en la nueva clase:
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>) {
//...
}
}
A continuación actualiza el método pushShortcut
para llamar a la API ShortcutManagerCompat
. Utiliza el siguiente código para actualizar la clase 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))
}
En la muestra de código anterior, pasamos appContext
a la API. Esta es una propiedad de clase que contiene un Contexto de la aplicación. Es importante usar un Contexto de la aplicación (en lugar de un Contexto de la actividad) para evitar fugas de memoria, ya que la retención del contexto podría durar más tiempo que el ciclo de vida de la actividad del host.
Además, la API requiere que pasemos un objeto ShortcutInfoCompat
para el objeto Task. En la muestra de código anterior, conseguimos esto llamando al método privado createShortcutCompat
, que actualizaremos para crear y mostrar un objeto ShortcutInfoCompat
. Para ello, tienes que actualizar el stub de createShortcutCompat
con el siguiente código:
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()
}
Los stubs restantes de funciones en esta clase permiten actualizar y borrar atajos dinámicos. Para habilitar esas funciones, actualízalas con el siguiente código:
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 })
}
Agrega la clase al localizador de servicios
Con la clase ShortcutsRepository
creada, el siguiente paso es hacer que las instancias de los objetos de esta clase estén disponibles para el resto de la app, que administra las dependencias de clase mediante la implementación del patrón del localizador de servicios. Abre la clase del localizador de servicios con el navegador de clases en Android Studio. Para ello, ve a Navigate > Class y escribe "ServiceLocator". Haz clic en el archivo Kotlin resultante para abrirlo en tu IDE.
En la parte superior de ServiceLocator.kt
, pega el siguiente código para importar los paquetes ShortcutsRepository
y 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
Para agregar los métodos y miembros del servicio ShortcutRepository
, pega el siguiente código en el cuerpo de 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)
}
}
}
Registra el servicio de atajos
El último paso es registrar tu nuevo servicio ShortcutsRepository
en la aplicación. En Android Studio, abre TodoApplication.kt
y copia el siguiente código cerca de la parte superior del archivo:
TodoApplication.kt
package com.example.android.architecture.blueprints.todoapp
/// ... Other import statements
import com.example.android.architecture.blueprints.todoapp.data.source.ShortcutsRepository
A continuación agrega el siguiente código al cuerpo de la clase para registrar el servicio:
TodoApplication.kt
//...
class TodoApplication : Application() {
//...
val shortcutsRepository: ShortcutsRepository
get() = ServiceLocator.provideShortcutsRepository(this)
//...
}
Compila la app y asegúrate de que siga ejecutándose.
5. Envía un atajo nuevo
Ahora que creaste el servicio de atajos, tienes todo listo para comenzar a enviar atajos. Dado que los usuarios generan contenido (elementos de tareas) en esta app y esperan poder consultarlo más adelante, habilitaremos el acceso por voz a ese contenido. Para ello, enviaremos un atajo dinámico que esté vinculado al BII GET_THING
cada vez que un usuario cree una tarea nueva. De esta manera, el Asistente puede llevar a los usuarios directamente al elemento de tarea solicitado cuando activan el BII pronunciando frases como "Hey Google, abre mi lista de compra de comestibles en App de Ejemplo".
Para habilitar esta funcionalidad en la app de ejemplo, sigue estos pasos:
- Importa el servicio
ShortcutsRepository
en la claseAddEditTaskViewModel
, que administra los objetos de la lista de tareas. - Envía un atajo dinámico cuando el usuario cree una tarea nueva.
Importa ShortcutsRepository
Primero necesitamos configurar el servicio ShortcutsRepository
de forma tal que esté disponible para AddEditTaskViewModel
. Para ello, importa el servicio a ViewModelFactory
, la clase de fábrica que usa la app para crear instancias de objetos ViewModel, lo que incluye AddEditTaskViewModel
.
Para abrir el navegador de clases en Android Studio, ve a Navigate > Class y escribe "ViewModelFactory". Haz clic en el archivo Kotlin resultante para abrirlo en tu IDE.
En la parte superior de ViewModelFactory.kt
, pega el siguiente código para importar los paquetes ShortcutsRepository
y SuppressLint
:
ViewModelFactory.kt
package com.example.android.architecture.blueprints.todoapp
// ...Other import statements
import com.example.android.architecture.blueprints.todoapp.data.source.ShortcutsRepository
A continuación reemplaza el cuerpo de ViewModelFactory
por el siguiente código:
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
}
Para finalizar los cambios de ViewModelFactory
, sube una capa y pasa ShortcutsRepository
al constructor de la fábrica. Abre el navegador de archivos de Android Studio. Para ello, ve a Navigate > File y escribe "FragmentExt.kt". Haz clic en el archivo Kotlin resultante, ubicado en el paquete util, para abrirlo en tu IDE.
Reemplaza el cuerpo de FragmentExt.kt
por el siguiente código:
fun Fragment.getViewModelFactory(): ViewModelFactory {
val taskRepository = (requireContext().applicationContext as TodoApplication).taskRepository
val shortcutsRepository = (requireContext().applicationContext as TodoApplication).shortcutsRepository
return ViewModelFactory(taskRepository, shortcutsRepository, this)
}
Envía un atajo
Con la clase de abstracción ShortcutsRepository
disponible para las clases ViewModel
de la app de ejemplo, puedes actualizar AddEditTaskViewModel
, la clase ViewModel
que se encarga de crear notas, para enviar un atajo dinámico cada vez que un usuario crea una nota nueva.
En Android Studio, abre el navegador de clases y escribe "AddEditTaskViewModel". Haz clic en el archivo Kotlin resultante para abrirlo en tu IDE.
En primer lugar, agrega el paquete ShortcutsRepository
a esa clase con la siguiente sentencia de importación:
package com.example.android.architecture.blueprints.todoapp.addedittask
//Other import statements
import com.example.android.architecture.blueprints.todoapp.data.source.ShortcutsRepository
A continuación actualiza el constructor de clase con el siguiente código para agregar la propiedad de clase shortcutsRepository
:
AddEditTaskViewModel.kt
//...
/**
* ViewModel for the Add/Edit screen.
*/
class AddEditTaskViewModel(
private val tasksRepository: TasksRepository,
private val shortcutsRepository: ShortcutsRepository
) : ViewModel() {
//...
Con la clase ShortcutsRepository
agregada, crea una nueva función, pushShortcut()
, para llamar a esa clase. Pega la siguiente función privada en el cuerpo de AddEditTaskViewModel
:
AddEditTaskViewModel.kt
//...
private fun pushShortcut(newTask: Task) = viewModelScope.launch {
shortcutsRepository.pushShortcut(newTask)
}
Por último, envía un nuevo atajo dinámico cada vez que se cree una tarea. Reemplaza el contenido de la función saveTask()
por el siguiente código:
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)
}
}
Prueba el código
Ya está todo listo para probar el código. En este paso, tienes que enviar un atajo dinámico habilitado por voz y también inspeccionarlo con la app del Asistente de Google.
Crea una vista previa
Crear una vista previa con el complemento Google Assistant permite que, en tu dispositivo de prueba, aparezcan atajos dinámicos en el Asistente.
Instala el complemento de prueba
Si aún no tienes el complemento Google Assistant, instálalo siguiendo estos pasos en Android Studio:
- Ve a **File > Settings (Android Studio > Preferences en MacOS).
- En la sección Plugins, accede a Marketplace y busca "Google Assistant".
- Si no encuentras el complemento en Marketplace, descárgalo manualmente y sigue las instrucciones que se indican en Install the plugin from disk.
- Instala la herramienta y reinicia Android Studio.
Crea la vista previa
Crea una vista previa siguiendo estos pasos en Android Studio:
- Haz clic en Tools > Google Assistant > "App Actions Test Tool".
- En el cuadro App name, define un nombre como "Lista de tareas pendientes".
- Haz clic en Create Preview. Si se te solicita, revisa y acepta las políticas y las Condiciones del Servicio de Acciones en apps.
Figura 3: Panel de creación de una vista previa en App Actions Test Tool
Durante las pruebas, los atajos dinámicos que envíes aparecerán en el Asistente organizados por nombre según lo que hayas indicado en App name para la vista previa.
Envía e inspecciona un atajo
Reinicia la app de ejemplo en tu dispositivo de prueba y sigue estos pasos:
- Crea una tarea nueva con el título "Iniciar codelab".
- Abre la app del Asistente de Google y di o escribe "Mis atajos".
- Presiona la pestaña Explorar. Deberías ver el atajo de ejemplo.
- Presiona el atajo para invocarlo. Deberías ver que la app se inicia con el nombre del atajo prepropagado en el cuadro de filtro, lo que facilita la búsqueda del elemento de tarea solicitado.
6. Actualiza y borra un atajo (opcional)
Además de enviar nuevos atajos dinámicos en el tiempo de ejecución, tu app puede actualizarlos para reflejar el estado actual de tu contenido y tus preferencias de usuario. Es conveniente que actualices los atajos existentes cada vez que un usuario modifique el elemento de destino; por ejemplo, al cambiarle el nombre a una tarea en nuestra app de ejemplo. Para evitar que el usuario vea atajos rotos, también tienes que borrar los atajos correspondientes cuando se haya quitado un recurso de destino.
Actualiza un atajo
Modifica AddEditTaskViewModel
para actualizar un atajo dinámico cada vez que un usuario cambie los detalles de un elemento de tarea. En primer lugar, actualiza el cuerpo de la clase con el siguiente código para agregar una función de actualización que utiliza nuestra clase de repositorio:
AddEditTaskViewModel.kt
private fun updateShortcut(newTask: Task) = viewModelScope.launch {
shortcutsRepository.updateShortcuts(listOf(newTask))
}
A continuación modifica la función saveTask()
para llamar a nuestro nuevo método cada vez que se actualice una tarea.
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)
}
}
Para probar el código, reinicia la app y sigue estos pasos:
- Cambia el nombre del título de tu elemento de tarea a "Finalizar codelab".
- Di "Hey Google, mis atajos" para abrir el Asistente de Google.
- Presiona la pestaña Explorar. Deberías ver una etiqueta corta actualizada para tu atajo de prueba.
Quita un atajo
Los atajos de nuestra app de ejemplo se deben quitar cada vez que un usuario borra una tarea. En la app de ejemplo, la lógica de eliminación de tareas se basa en la clase TaskDetailViewModel
. Antes de actualizar esta clase, debemos actualizar ViewModelFactory
nuevamente para pasar shortcutsRepository
a TaskDetailViewModel
.
Abre ViewModelFactory
y reemplaza el contenido de su método de constructor con el siguiente código:
//...
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
}
A continuación abre TaskDetailViewModel
. Importa el módulo ShortcutsRepository
y declara una variable de instancia para ese módulo con el siguiente código:
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() {
...
}
Por último, modifica la función deleteTask()
para que llame a shortcutsRepository
y quite el atajo según su ID cada vez que se borre una tarea con un taskId
correspondiente:
TaskDetailViewModel.kt
fun deleteTask() = viewModelScope.launch {
_taskId.value?.let {
//...
shortcutsRepository.removeShortcutsById(listOf(it))
}
}
Para probar el código, reinicia la app y sigue estos pasos:
- Borra tu tarea de prueba.
- Cambia el nombre del título de tu elemento de tarea a "Finalizar codelab".
- Di "Hey Google, mis atajos" para abrir el Asistente de Google.
- Presiona la pestaña Explorar. Verifica que ya no aparezca tu atajo de prueba.
7. Próximos pasos
¡Felicitaciones! Gracias a tu trabajo, los usuarios de nuestra app de ejemplo pueden pedirle al Asistente cosas como "Hey Google, abre mi lista de compra de comestibles en App de Ejemplo" para regresar fácilmente a las notas que crean en esa app. Los atajos fomentan la participación de los usuarios, ya que facilitan la repetición de acciones frecuentes en tu app.
Temas abordados
En este codelab, aprendiste a hacer lo siguiente:
- Identificar casos de uso para enviar atajos dinámicos en una app
- Reducir la complejidad del código mediante patrones de diseño de repositorios, inserción de dependencias y localizadores de servicios
- Enviar atajos dinámicos habilitados por voz al contenido de la app generado por los usuarios
- Actualizar y quitar atajos existentes
¿Qué sigue?
De ahora en adelante, puedes definir mejor tu app de listas de tareas. Para consultar el proyecto finalizado, accede al repositorio de la rama –codelab-complete en GitHub.
A continuación, presentamos algunas sugerencias para adquirir más conocimientos sobre cómo configurar esta app con Acciones en apps:
- Para aprender a hacer un seguimiento del rendimiento de tus Acciones en apps, consulta el ejemplo de listas de tareas pendientes con Google Analytics para Firebase.
- Consulta la referencia de intents integrados de Acciones en apps para descubrir otras maneras de implementar el Asistente en tus apps.
Para continuar tu recorrido de Actions on Google, explora estos recursos:
- actions.google.com (sitio de documentación oficial sobre Actions on Google)
- Índice de muestra de Acciones en apps (apps de ejemplo y código de muestra para explorar las capability °de Acciones en apps)
- Repositorio de Actions on Google en GitHub (código de muestra y bibliotecas)
- r/GoogleAssistantDev (comunidad oficial de Reddit para desarrolladores que trabajan con el Asistente de Google)
Síguenos en Twitter (@ActionsOnGoogle) para mantenerte al tanto de nuestros anuncios más recientes y utiliza el hashtag #appActions para compartir tus compilaciones.
Encuesta de comentarios
Por último, completa esta encuesta para enviarnos comentarios sobre tu experiencia con este codelab.