Estendi le scorciatoie dinamiche all'Assistente Google con Azioni app

1. Panoramica

Nel codelab precedente, hai usato scorciatoie statiche per implementare gli intent integrati (BII) comunemente utilizzati in un'app di esempio. Gli sviluppatori Android usano Azioni app per estendere la funzionalità delle app all'Assistente Google.

Le scorciatoie statiche sono incluse in un'app e possono essere aggiornate solo rilasciando nuove versioni dell'app. L'attivazione della funzionalità vocale per gli elementi dinamici di un'app, ad esempio i contenuti generati dagli utenti, viene eseguita utilizzando le scorciatoie dinamiche. Le app eseguono il push delle scorciatoie dinamiche dopo che gli utenti eseguono azioni pertinenti, come creare una nuova nota in un'app di monitoraggio delle attività. Con Azioni app, puoi attivare queste scorciatoie per la voce associandole a un intent integrato, consentendo agli utenti di accedere ai propri contenuti dall'assistente dicendo, ad esempio, "Hey Google, apri la mia lista della spesa su ExampleApp".

Tre schermate progressive che mostrano l'Assistente Google che avvia una scorciatoia dinamica.

Figura 1. Tre schermate progressive che mostrano un'attività creata dall'utente e l'Assistente Google che lancia una scorciatoia dinamica per l'elemento dell'attività.

Cosa creerai

In questo codelab, abiliterai le scorciatoie dinamiche per la voce in un'app Android con un elenco di cose da fare di esempio, consentendo agli utenti di chiedere all'assistente di aprire gli elementi dell'elenco di attività che creano nell'app. Puoi farlo utilizzando i pattern di architettura Android, in particolare i pattern di repository, service locator e ViewModel.

Prerequisiti

Questo codelab si basa sui concetti delle Azioni app trattati nel codelab precedente, in particolare intent integrati e scorciatoie statiche. Se non hai mai utilizzato Azioni app, ti consigliamo di completare il codelab prima di continuare.

Inoltre, prima di procedere, assicurati che l'ambiente di sviluppo abbia la seguente configurazione:

  • Un terminale per eseguire i comandi della shell con Git installato.
  • L'ultima release stabile di Android Studio.
  • Un dispositivo Android fisico o virtuale con accesso a internet.
  • Un Account Google con cui è stato eseguito l'accesso ad Android Studio, all'app Google e all'app Assistente Google.

2. Come funziona

L'attivazione di una scorciatoia dinamica per l'accesso vocale prevede i seguenti passaggi:

  • Associazione di una scorciatoia dinamica a un intent integrato idoneo.
  • È in corso l'attivazione dell'assistente per importare le scorciatoie aggiungendo la libreria di integrazione delle scorciatoie di Google.
  • Inviare una scorciatoia ogni volta che un utente completa l'attività in-app pertinente.

Scorciatoie di associazione

Affinché una scorciatoia dinamica sia accessibile dall'assistente, deve essere associata a un intent integrato pertinente. Quando viene attivato un intent integrato con una scorciatoia, l'assistente associa i parametri nella richiesta dell'utente alle parole chiave definite nella scorciatoia associata. Ad esempio:

  • Una scorciatoia associata all'intent integrato GET_THING potrebbe consentire agli utenti di richiedere contenuti in-app specifici direttamente dall'assistente. * "Hey Google, apri la lista della spesa su ExampleApp."
  • Una scorciatoia associata all'intent integrato ORDER_MENU_ITEM potrebbe consentire agli utenti di riprodurre gli ordini precedenti. * "Hey Google, ordina il mio solito su ExampleApp."

Per un elenco completo categorizzato di intent integrati, consulta Riferimento per gli intent integrati.

Fornire scorciatoie all'assistente

Dopo aver associato le scorciatoie a un intent integrato, il passaggio successivo è consentire all'assistente di importare queste scorciatoie aggiungendo la libreria di integrazione delle scorciatoie di Google al tuo progetto. Con questa libreria attiva, l'assistente sarà a conoscenza di ogni scorciatoia inviata dalla tua app, consentendo agli utenti di avviarle usando la frase di attivazione della scorciatoia nell'assistente.

3. Prepara l'ambiente di sviluppo

Questo codelab utilizza un'app di esempio per l'elenco di cose da fare realizzata per Android. Con questa app, gli utenti possono aggiungere articoli agli elenchi, cercare voci di attività per categoria e filtrare le attività in base allo stato di completamento. Scarica e prepara l'app di esempio completando questa sezione.

Scarica i tuoi file di base

Esegui questo comando per clonare il repository GitHub dell'app di esempio:

git clone https://github.com/actions-on-google/app-actions-dynamic-shortcuts.git

Una volta clonato il repository, segui questi passaggi per aprirlo in Android Studio:

  1. Nella finestra di dialogo Ti diamo il benvenuto in Android Studio, fai clic su Importa progetto.
  2. Seleziona la cartella in cui hai clonato il repository.

In alternativa, puoi visualizzare una versione dell'app di esempio che rappresenta il codelab completato clonando il ramo codelab-complete del relativo repository GitHub:

git clone https://github.com/actions-on-google/app-actions-dynamic-shortcuts.git --branch codelab-complete

Aggiornare l'ID app per Android

L'aggiornamento dell'ID applicazione dell'app identifica in modo univoco l'app sul dispositivo di test ed evita un "Nome pacchetto duplicato" se l'app viene caricata su Play Console. Per aggiornare l'ID applicazione, apri app/build.gradle:

android {
...
  defaultConfig {
    applicationId "com.MYUNIQUENAME.android.fitactions"
    ...
  }
}

Sostituisci "MYUNIQUENAME" nel campo applicationId a qualcosa di tuo.

Aggiungi dipendenze API Shortcuts

Aggiungi le seguenti librerie Jetpack al file di risorse 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'
   ...
}

Testa l'app sul tuo dispositivo

Prima di apportare altre modifiche all'app, è utile avere un'idea di cosa può fare l'app di esempio. Per eseguire l'app sull'emulatore, segui questi passaggi:

  1. In Android Studio, seleziona Esegui > Esegui l'app o fai clic su EseguiIcona Esegui app in Android Studio nella barra degli strumenti.
  2. Nella finestra di dialogo Seleziona la destinazione del deployment, seleziona un dispositivo e fai clic su OK. La versione del sistema operativo consigliata è Android 10 (livello API 30) o versioni successive, anche se le Azioni app funzionano sui dispositivi fino ad Android 5 (livello API 21).
  3. Tieni premuto a lungo il pulsante Home per configurare l'assistente e verificare che funzioni. Dovrai accedere all'assistente sul tuo dispositivo, se non l'hai ancora fatto.

Per saperne di più sui dispositivi virtuali Android, vedi Creare e gestire dispositivi virtuali.

Esplora brevemente l'app per vedere cosa sa fare. Se tocchi l'icona Più, viene creata una nuova voce di attività. Le voci di menu in alto a destra ti consentono di cercare e filtrare le voci delle attività in base allo stato di completamento.

4. Crea una classe di repository delle scorciatoie

Diverse classi nella nostra app di esempio chiameranno l'API ShortcutManagerCompat per eseguire il push e gestire le scorciatoie dinamiche. Per ridurre la ridondanza del codice, implementerai un repository per consentire alle tue classi di progetto di gestire facilmente le scorciatoie dinamiche.

Il pattern di progettazione del repository fornisce un'API pulita per la gestione delle scorciatoie. Il vantaggio di un repository è che i dettagli dell'API sottostante sono uniformemente astratti dietro un'API minima. Implementa il repository seguendo questi passaggi:

  1. Crea una classe ShortcutsRepository per astrarre l'API ShortcutManagerCompat.
  2. Aggiungi i metodi ShortcutsRepository al Service Locator dell'app.
  3. Registra il servizio ShortcutRepository nell'applicazione principale.

crea il repository

Crea una nuova classe Kotlin denominata ShortcutsRepository nel pacchetto com.example.android.architecture.blueprints.todoapp.data.source. Puoi trovare questo pacchetto organizzato nella cartella app/src/main/java. Utilizzerai questa lezione per implementare un'interfaccia che offra un insieme minimo di metodi per coprire il caso d'uso del nostro codelab.

Finestra di Android Studio che mostra la posizione della classe ShortcutsRepository.

Figura 2. Finestra File di progetto Android Studio che mostra la posizione della classe ShortcutsRepository.

Incolla il codice seguente nella nuova classe:

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>) {
       //...
   }
}

Aggiorna il metodo pushShortcut per chiamare l'API ShortcutManagerCompat. Aggiorna la classe ShortcutsRepository con il seguente codice:

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))
}

Nell'esempio di codice precedente abbiamo passato appContext all'API. Questa è una proprietà di classe che contiene un Contesto applicazione. È importante utilizzare un contesto dell'applicazione (e non un contesto dell'attività) per evitare fughe di memoria, poiché il contesto potrebbe essere conservato più a lungo del ciclo di vita dell'attività dell'host.

Inoltre, l'API richiede che passiamo un oggetto ShortcutInfoCompat per l'oggetto Tasks. Nell'esempio di codice precedente, eseguiamo questa operazione chiamando il metodo privato createShortcutCompat, che aggiorneremo per creare e restituire un oggetto ShortcutInfoCompat. A questo scopo, aggiorna lo stub createShortcutCompat con il seguente codice:

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()
}

Gli altri moduli di funzione di questa classe riguardano l'aggiornamento e l'eliminazione delle scorciatoie dinamiche. Attiva queste funzioni aggiornandole con il seguente codice:

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 })
}

Aggiungi classe a Localizzatore servizio

Dopo aver creato la classe ShortcutsRepository, il passaggio successivo consiste nel rendere disponibili le istanze degli oggetti di questa classe al resto dell'app. Questa app gestisce le dipendenze delle classi implementando il pattern Service Locator. Apri la classe Service locator utilizzando il browser del corso in Android Studio selezionando Naviga > Class e digitando "ServiceLocator". Fai clic sul file Kotlin risultante per aprirlo nel tuo IDE.

Incolla il codice seguente nella parte superiore di ServiceLocator.kt per importare i pacchetti ShortcutsRepository e 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

Aggiungi i membri e i metodi del servizio ShortcutRepository incollando il codice seguente nel corpo di 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 il servizio scorciatoia

Il passaggio finale consiste nel registrare il nuovo servizio ShortcutsRepository nell'Applicazione. In Android Studio, apri TodoApplication.kt e copia il codice seguente nella parte superiore del file:

TodoApplication.kt

package com.example.android.architecture.blueprints.todoapp
/// ... Other import statements

import com.example.android.architecture.blueprints.todoapp.data.source.ShortcutsRepository

Quindi, registra il servizio aggiungendo il seguente codice al corpo della classe:

TodoApplication.kt

//...
class TodoApplication : Application() {

   //...

   val shortcutsRepository: ShortcutsRepository
       get() = ServiceLocator.provideShortcutsRepository(this)

   //...
}

Crea l'app e assicurati che continui a essere eseguita.

5. Esegui il push di una nuova scorciatoia

Una volta creato il servizio scorciatoia, puoi iniziare a trasferire le scorciatoie. Poiché gli utenti generano contenuti (elementi di attività) in questa app e si aspettano di potervi tornare in un secondo momento, abiliteremo l'accesso vocale a questi contenuti inviando una scorciatoia dinamica associata all'intent integrato GET_THING ogni volta che un utente crea una nuova attività. In questo modo l'assistente può avviare gli utenti direttamente sull'elemento dell'attività richiesto quando attivano l'intent integrato chiedendo, ad esempio, "Hey Google, apri la mia lista della spesa su SampleApp".

Abiliti questa funzionalità nell'app di esempio completando questi passaggi:

  1. Importazione del servizio ShortcutsRepository nella classe AddEditTaskViewModel, responsabile della gestione degli oggetti dell'elenco di attività.
  2. Invio di una scorciatoia dinamica quando l'utente crea una nuova attività.

Importa ShortcutsRepository

Dobbiamo prima rendere disponibile il servizio ShortcutsRepository per AddEditTaskViewModel. A questo scopo, importa il servizio in ViewModelFactory, la classe di fabbrica utilizzata dall'app per creare un'istanza degli oggetti ViewModel, tra cui AddEditTaskViewModel.

Apri il browser del corso in Android Studio: Naviga > Class e digitando "ViewModelFA". Fai clic sul file Kotlin risultante per aprirlo nel tuo IDE.

Incolla il codice seguente nella parte superiore di ViewModelFactory.kt per importare i pacchetti ShortcutsRepository e SuppressLint:

ViewModelFactory.kt

package com.example.android.architecture.blueprints.todoapp

// ...Other import statements
import com.example.android.architecture.blueprints.todoapp.data.source.ShortcutsRepository

Poi, sostituisci il corpo di ViewModelFactory con il seguente codice:

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
}

Termina le modifiche ViewModelFactory salendo di un livello e passa ShortcutsRepository al costruttore della fabbrica. Apri il browser di file di Android Studio andando su Naviga > File e digita "FragmentExt.kt". Fai clic sul file Kotlin risultante nel pacchetto util per aprirlo nel tuo IDE.

Sostituisci il corpo di FragmentExt.kt con il seguente codice:

fun Fragment.getViewModelFactory(): ViewModelFactory {
   val taskRepository = (requireContext().applicationContext as TodoApplication).taskRepository
   val shortcutsRepository = (requireContext().applicationContext as TodoApplication).shortcutsRepository
   return ViewModelFactory(taskRepository, shortcutsRepository, this)
}

Esegui il push di una scorciatoia

Con la classe di astrazione ShortcutsRepository disponibile per le classi ViewModel dell'app di esempio, aggiorni AddEditTaskViewModel, la classe ViewModel responsabile della creazione delle note, in modo da eseguire il push di una scorciatoia dinamica ogni volta che un utente crea una nuova nota.

In Android Studio, apri il browser della classe e digita "AddEditTaskViewModel". Fai clic sul file Kotlin risultante per aprirlo nel tuo IDE.

Innanzitutto, aggiungi il pacchetto ShortcutsRepository a questa classe con la seguente istruzione di importazione:

package com.example.android.architecture.blueprints.todoapp.addedittask

//Other import statements
import com.example.android.architecture.blueprints.todoapp.data.source.ShortcutsRepository

In seguito, aggiungi la proprietà della classe shortcutsRepository aggiornando il costruttore della classe con il seguente codice:

AddEditTaskViewModel.kt

//...

/**
* ViewModel for the Add/Edit screen.
*/
class AddEditTaskViewModel(
   private val tasksRepository: TasksRepository,
   private val shortcutsRepository: ShortcutsRepository
) : ViewModel() {

    //...

Con la classe ShortcutsRepository aggiunta, crea una nuova funzione, pushShortcut(), per chiamare questa classe. Incolla la seguente funzione privata nel corpo di AddEditTaskViewModel:

AddEditTaskViewModel.kt

//...
private fun pushShortcut(newTask: Task) = viewModelScope.launch {
   shortcutsRepository.pushShortcut(newTask)
}

Infine, esegui il push di una nuova scorciatoia dinamica ogni volta che viene creata un'attività. Sostituisci i contenuti della funzione saveTask() con il seguente codice:

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)
    }
}

Prova il codice

Siamo finalmente pronti a testare il nostro codice! In questo passaggio, premi una scorciatoia dinamica con riconoscimento vocale e la ispezionirai utilizzando l'app Assistente Google.

Creare un'anteprima

La creazione di un'anteprima con il plug-in dell'Assistente Google consente di visualizzare le scorciatoie dinamiche nell'assistente sul dispositivo di test.

Installa il plug-in di prova

Se non hai ancora il plug-in dell'Assistente Google, installalo seguendo questa procedura in Android Studio:

  1. Vai a **File > Impostazioni (Android Studio > Preferenze su macOS).
  2. Nella sezione plugin, vai a Marketplace e cerca "Google Assistant" (Assistente Google).
  3. Installa lo strumento e riavvia Android Studio.

Crea l'anteprima

Per creare un'anteprima in Android Studio, procedi nel seguente modo:

  1. Fai clic su Strumenti > Assistente Google > "Strumento di test delle Azioni app".
  2. Nella casella Nome app, definisci un nome come "Elenco di cose da fare".
  3. Fai clic su Crea anteprima. Se richiesto, leggi e accetta le norme e i termini di servizio di Azioni app.

Riquadro di creazione dell&#39;anteprima dello strumento App Actions Test Tool.

Figura 3. Riquadro di creazione dell'anteprima dello strumento App Actions Test Tool.

Durante il test, le scorciatoie dinamiche che invii all'assistente verranno visualizzate nell'assistente organizzate in base al nome dell'app fornito per l'anteprima.

Esegui il push e ispeziona una scorciatoia

Riavvia l'app di esempio sul dispositivo di test ed esegui queste operazioni :

  1. Crea una nuova attività dal titolo "Avvia codelab"
  2. Apri l'app Assistente Google e di' o digita: "Le mie scorciatoie".
  3. Tocca la scheda Esplora. Dovresti visualizzare la scorciatoia di esempio.
  4. Tocca la scorciatoia per richiamarla. L'avvio dell'app dovrebbe essere visualizzato con il nome della scorciatoia precompilato nella casella dei filtri, in modo da poter trovare facilmente l'elemento dell'attività richiesto.

6. (Facoltativo) Aggiorna ed elimina una scorciatoia

Oltre a inviare nuove scorciatoie dinamiche in fase di runtime, la tua app può aggiornarle per riflettere lo stato corrente dei contenuti e delle preferenze dell'utente. È buona norma aggiornare le scorciatoie esistenti ogni volta che un utente modifica l'elemento di destinazione, ad esempio rinominando un'attività nella nostra app di esempio. Devi eliminare una scorciatoia corrispondente anche ogni volta che la risorsa di destinazione viene rimossa, per evitare di mostrare agli utenti scorciatoie non funzionanti.

Aggiornare una scorciatoia

Modifica AddEditTaskViewModel per aggiornare una scorciatoia dinamica ogni volta che un utente modifica i dettagli di un elemento dell'attività. Per prima cosa, aggiorna il corpo della classe con il codice seguente per aggiungere una funzione di aggiornamento che utilizzi la nostra classe di repository:

AddEditTaskViewModel.kt

private fun updateShortcut(newTask: Task) = viewModelScope.launch {
   shortcutsRepository.updateShortcuts(listOf(newTask))
}

Successivamente, modifica la funzione saveTask() per chiamare il nuovo metodo ogni volta che viene aggiornata un'attività esistente.

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)
   }
}

Testa il codice riavviando l'app e seguendo questa procedura:

  1. Rinomina il titolo dell'elemento dell'attività esistente in "Termina codelab".
  2. Apri l'Assistente Google dicendo "Hey Google, le mie scorciatoie".
  3. Tocca la scheda Esplora. Dovresti vedere un'etichetta breve aggiornata per la scorciatoia di prova.

Rimuovere una scorciatoia

Le nostre scorciatoie app di esempio dovrebbero essere rimosse ogni volta che un utente elimina un'attività. Nell'app di esempio, la logica di eliminazione delle attività si trova nella classe TaskDetailViewModel. Prima di aggiornare questo corso, dobbiamo aggiornare di nuovo ViewModelFactory per trasferire shortcutsRepository a TaskDetailViewModel.

Apri ViewModelFactory e sostituisci i contenuti del relativo metodo costruttore con il seguente codice:

//...
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
}

Dopodiché apri TaskDetailViewModel. Importa il modulo ShortcutsRepository e dichiara una variabile di istanza utilizzando il seguente codice:

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() {
...
}

Infine, modifica la funzione deleteTask() per chiamare shortcutsRepository in modo da rimuovere una scorciatoia basata sul suo ID ogni volta che viene eliminata un'attività con un taskId corrispondente:

TaskDetailViewModel.kt

fun deleteTask() = viewModelScope.launch {
   _taskId.value?.let {
       //...
       shortcutsRepository.removeShortcutsById(listOf(it))
   }
}

Per testare il codice, riavvia l'app e segui questi passaggi:

  1. Elimina l'attività di test.
  2. Rinomina il titolo dell'elemento dell'attività esistente in "Termina codelab".
  3. Apri l'Assistente Google dicendo "Hey Google, le mie scorciatoie".
  4. Tocca la scheda Esplora. Verifica che la scorciatoia per il test non venga più visualizzata.

7. Passaggi successivi

Complimenti! Grazie a te, gli utenti della nostra app di esempio possono tornare facilmente alle note che creano chiedendo all'assistente, ad esempio, "Hey Google, apri la mia lista della spesa su ExampleApp". Le scorciatoie favoriscono un maggiore coinvolgimento degli utenti consentendo loro di riprodurre facilmente le azioni utilizzate di frequente nella tua app.

Argomenti trattati

In questo codelab, hai imparato a:

  • Identificare i casi d'uso per il push delle scorciatoie dinamiche in un'app.
  • Riduci la complessità del codice utilizzando repository, inserimento di dipendenze e pattern di progettazione di Service locator.
  • Trasferisci le scorciatoie dinamiche che supportano i comandi vocali ai contenuti delle app generati dagli utenti.
  • Aggiorna e rimuovi le scorciatoie esistenti.

Passaggi successivi

Da qui, puoi provare ad apportare ulteriori perfezionamenti all'app Elenco attività. Per fare riferimento al progetto finito, consulta il ramo del repository –codelab-complete su GitHub.

Ecco alcuni suggerimenti per ulteriori informazioni su come estendere questa app con Azioni app:

Per continuare il tuo percorso con Actions on Google, esplora queste risorse:

Seguici su Twitter @ActionsOnGoogle per non perderti i nostri ultimi annunci e twitta a #appActions per condividere ciò che hai realizzato.

Sondaggio di feedback

Infine, ti invitiamo a rispondere a questo sondaggio per fornire un feedback sulla tua esperienza con questo codelab.