Interagir com blocos

Os blocos podem fazer mais do que apenas mostrar informações. Eles também podem ser interativos. Para fazer com que um elemento, como textButton(), responda a toques, gere um manipulador de clique usando clickable() e o associe ao elemento de layout.

É possível configurar um Clickable para acionar uma ação de duas maneiras principais:

  1. Iniciar uma atividade diretamente: use launchAction() para casos em que você precisa abrir uma atividade imediatamente.
  2. Delegar ao serviço de Bloco: use loadAction() para acionar a lógica no TileService. Essa é uma abordagem mais flexível que permite atualizar o conteúdo do bloco, atualizar o estado dele ou iniciar uma atividade mais complexa.

Iniciar uma atividade exportada

Se um toque do usuário precisar iniciar uma atividade imediatamente, use launchAction(). Forneça uma ComponentName para identificar a atividade. A atividade precisa ser exportada. Com essa abordagem, é possível transmitir extras Intent com a ação. No entanto, não é possível definir flags Intent personalizadas.

O exemplo a seguir mostra como criar uma Clickable para iniciar TileActivity com dois extras, name e age:

textButton(
    labelContent = {
        text("launchAction()".layoutString, typography = BODY_LARGE)
    },
    onClick =
    clickable(
        action =
        launchAction(
            ComponentName(
                "com.example.wear",
                "com.example.wear.snippets.m3.tile.TileActivity",
            ),
            mapOf(
                "name" to ActionBuilders.stringExtra("Bartholomew"),
                "age" to ActionBuilders.intExtra(21),
            ),
        )
    ),
)

Na atividade iniciada, extraia os valores dos extras da intent:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    // When this activity is launched from the tile InteractionLaunchAction,
    // "name" will be "Bartholomew" and "age" will be 21
    val name = intent.getStringExtra("name")
    val age = intent.getStringExtra("age")

    // ...
}

Processar interações no serviço de Bloco

Para interações mais flexíveis, use loadAction(). Quando um usuário toca em um elemento configurado com loadAction, o sistema invoca novamente o TileService.onTileRequest(). Isso permite executar a lógica no serviço para atualizar o bloco, mudar o estado dele e realizar tarefas mais complexas.

Atualizar o conteúdo do bloco

O uso mais simples de loadAction é sinalizar uma atualização. Chame loadAction sem argumentos. Quando tocado, o sistema chama onTileRequest(), permitindo que o serviço retorne um novo layout com conteúdo atualizado.

textButton(
    onClick = clickable(loadAction()),
    labelContent = { text("Refresh".layoutString) },
)

Distinguir entre vários elementos interativos

Se o bloco tiver vários elementos interativos, você poderá associar um ID ao modificador Clickable:

No onTileRequest(), você pode verificar esse ID usando requestParams.currentState.lastClickableId para decidir qual ação realizar.

Exemplo: como iniciar uma atividade com um link direto

Esse padrão é ideal para iniciar uma atividade com um link direto. O toque do usuário recarrega o bloco, seu serviço inspeciona o ID e inicia a nova atividade. Para controlar a backstack, use um TaskStackBuilder e ofereça uma experiência de navegação melhor para o usuário. Quando o usuário toca no elemento, ele é direcionado diretamente para a tela com link direto (a tela message_detail/1 do exemplo). Como .addNextIntentWithParentStack() foi usado, a atividade pai também é adicionada à backstack. Isso significa que, se o usuário deslizar para trás, ele vai navegar até a tela principal do app (MessageList no exemplo) em vez de sair imediatamente para o bloco. Deslizar de volta uma segunda vez os leva de volta ao bloco.

Em seguida, em TileActivity, configure a navegação para corresponder ao padrão googleandroidsnippets://app/message_detail/{id}.

Use TaskStackBuilder para oferecer uma melhor experiência de navegação ao usuário. Quando o usuário toca no elemento, ele é direcionado diretamente para a tela com link direto. Neste exemplo, é a tela message_detail/1. Como .addNextIntentWithParentStack() foi usado, a atividade pai também é adicionada à backstack. Isso significa que, se o usuário deslizar para trás, ele vai navegar até a tela principal do app (MessageList no exemplo) em vez de sair imediatamente para o bloco. Deslizar para trás uma segunda vez retorna os itens ao bloco.

Atualizar o estado dentro do bloco

Seu bloco tem um objeto StateBuilders.State que armazena pares de chave-valor e persiste em recarregar. Use loadAction() para atualizar esse estado quando um usuário interagir com o Bloco.

Para fazer isso, transmita um DynamicDataMap para loadAction() contendo os novos valores de estado.

textButton(
    labelContent = {
        text("loadAction()".layoutString, typography = BODY_LARGE)
    },
    onClick =
    clickable(
        action =
        loadAction(
            dynamicDataMapOf(
                stringAppDataKey("name") mapTo "Javier",
                intAppDataKey("age") mapTo 37,
            )
        )
    ),
)

Quando onTileRequest() é acionado por essa ação, é possível ler os dados atualizados de requestParams.currentState.stateMap. Isso é útil para interações que modificam diretamente os dados no Bloco, como incrementar um contador ou alternar uma configuração.

override fun onTileRequest(
    requestParams: RequestBuilders.TileRequest
): ListenableFuture<Tile> {

    // When triggered by loadAction(), "name" will be "Javier", and "age" will
    // be 37.
    with(requestParams.currentState.stateMap) {
        val name = this[stringAppDataKey("name")]
        val age = this[intAppDataKey("age")]
    }

    // ...
}