Crie blocos com conteúdo que muda com o passar do tempo.
Trabalhar com linhas do tempo
Uma linha do tempo consiste em uma ou mais instâncias de
TimelineEntry
,
cada uma com um layout mostrado durante um
intervalo de tempo específico. Todos os blocos precisam de uma linha do tempo.
Blocos de entrada única
Geralmente, um bloco pode ser descrito com uma única TimelineEntry
. O layout é
fixo, e apenas as informações contidas nele mudam. Por exemplo, um bloco
que mostra o progresso de condicionamento físico do dia sempre tem o mesmo layout de progresso,
embora você possa o ajustar para mostrar valores diferentes. Nesses
casos, você não sabe com antecedência quando o conteúdo pode mudar.
Confira este exemplo de um bloco com uma única TimelineEntry
:
Kotlin
override fun onTileRequest( requestParams: TileRequest ): ListenableFuture<Tile> { val tile = Tile.Builder() .setResourcesVersion(RESOURCES_VERSION) // We add a single timeline entry when our layout is fixed, and // we don't know in advance when its contents might change. .setTileTimeline( Timeline.fromLayoutElement(...) ).build() return Futures.immediateFuture(tile) }
Java
@Override protected ListenableFuture<Tile> onTileRequest( @NonNull TileRequest requestParams ) { Tile tile = new Tile.Builder() .setResourcesVersion(RESOURCES_VERSION) // We add a single timeline entry when our layout is fixed, and // we don't know in advance when its contents might change. .setTileTimeline( Timeline.fromLayoutElement(...) ).build(); return Futures.immediateFuture(tile); }
Entradas da linha do tempo com prazos
Uma TimelineEntry
pode definir um período de validade, permitindo que um bloco
mude o layout em um momento conhecido sem precisar que o app envie um novo bloco.
O exemplo canônico é um bloco de agenda com uma lista de eventos futuros. Cada evento futuro contém um período de validade para indicar quando será mostrado.
A API Tiles permite a sobreposição de períodos de validade, em que a tela com o menor período restante é mostrada. Apenas um evento aparece por vez.
Os desenvolvedores podem fornecer uma entrada substituta padrão. Por exemplo, o bloco de agenda pode ter um bloco com um período de validade infinito, que vai ser usado se nenhuma outra entrada da linha do tempo for válida, conforme mostrado no exemplo de código abaixo:
Kotlin
public override fun onTileRequest( requestParams: TileRequest ): ListenableFuture<Tile> { val timeline = Timeline.Builder() // Add fallback "no meetings" entry // Use the version of TimelineEntry that's in androidx.wear.protolayout. timeline.addTimelineEntry(TimelineEntry.Builder() .setLayout(getNoMeetingsLayout()) .build() ) // Retrieve a list of scheduled meetings val meetings = MeetingsRepo.getMeetings() // Add a timeline entry for each meeting meetings.forEach { meeting -> timeline.addTimelineEntry(TimelineEntry.Builder() .setLayout(getMeetingLayout(meeting)) .setValidity( // The tile should disappear when the meeting begins // Use the version of TimeInterval that's in // androidx.wear.protolayout. TimeInterval.Builder() .setEndMillis(meeting.dateTimeMillis).build() ).build() ) } val tile = Tile.Builder() .setResourcesVersion(RESOURCES_VERSION) .setTileTimeline(timeline.build()) .build() return Futures.immediateFuture(tile) }
Java
@Override protected ListenableFuture<Tile> onTileRequest( @NonNull RequestBuilders.TileRequest requestParams ) { Timeline.Builder timeline = new Timeline.Builder(); // Add fallback "no meetings" entry // Use the version of TimelineEntry that's in androidx.wear.protolayout. timeline.addTimelineEntry(new TimelineEntry.Builder().setLayout(getNoMeetingsLayout()).build()); // Retrieve a list of scheduled meetings List<Meeting> meetings = MeetingsRepo.getMeetings(); // Add a timeline entry for each meeting for(Meeting meeting : meetings) { timeline.addTimelineEntry(new TimelineEntry.Builder() .setLayout(getMeetingLayout(meeting)) .setValidity( // The tile should disappear when the meeting begins // Use the version of TimeInterval that's in // androidx.wear.protolayout. new TimeInterval.builder() .setEndMillis(meeting.getDateTimeMillis()).build() ).build() ); } Tile tile = new Tile.Builder() .setResourcesVersion(RESOURCES_VERSION) .setTileTimeline(timeline.build()) .build(); return Futures.immediateFuture(tile); }
Atualizar um bloco
As informações mostradas em um bloco podem expirar depois de um tempo. Por exemplo, um bloco de clima que mostra a mesma temperatura ao longo do dia não é exato.
Para gerenciar dados prestes a expirar, defina um intervalo de atualização no momento da criação do bloco, que especifica por quanto tempo ele é válido. No exemplo do bloco de clima, você pode atualizar o conteúdo a cada hora, conforme mostrado no exemplo de código abaixo:
Kotlin
override fun onTileRequest(requestParams: RequestBuilders.TileRequest) = Futures.immediateFuture(Tile.Builder() .setResourcesVersion(RESOURCES_VERSION) .setFreshnessIntervalMillis(60 * 60 * 1000) // 60 minutes .setTileTimeline(Timeline.fromLayoutElement( getWeatherLayout()) ).build() )
Java
@Override protected ListenableFuture<Tile> onTileRequest( @NonNull TileRequest requestParams ) { return Futures.immediateFuture(new Tile.Builder() .setResourcesVersion(RESOURCES_VERSION) .setFreshnessIntervalMillis(60 * 60 * 1000) // 60 minutes .setTimeline(Timeline.fromLayoutElement( getWeatherLayout()) ).build()); }
Quando você define um intervalo de atualização, o sistema chama
onTileRequest()
logo após o fim do intervalo. Se você não definir um intervalo de atualização, o
sistema não vai chamar onTileRequest()
.
Um bloco também pode expirar devido a um evento externo. Por exemplo, um usuário pode remover uma reunião da agenda dele. Se o bloco não for atualizado, ele ainda vai mostrar essa reunião excluída. Nesse caso, solicite uma atualização de qualquer lugar no código do aplicativo, conforme mostrado no exemplo de código abaixo:
Kotlin
fun eventDeletedCallback() { TileService.getUpdater(context) .requestUpdate(MyTileService::class.java) }
Java
public void eventDeletedCallback() { TileService.getUpdater(context) .requestUpdate(MyTileService.class); }
Escolher um fluxo de trabalho de atualização
Siga estas práticas recomendadas para determinar como configurar as atualizações de blocos:
- Use uma linha do tempo se a atualização for previsível, por exemplo, no próximo evento da agenda do usuário.
- Ao buscar dados da plataforma, use a vinculação de dados para que o sistema atualize os dados automaticamente.
Se a atualização puder ser calculada no dispositivo em um curto período, como atualizar a posição de uma imagem em um bloco do nascer do sol, use
onTileRequest()
.Isso é particularmente útil quando você precisa gerar todas as imagens com antecedência. Se você precisar gerar uma nova imagem no futuro, chame
setFreshnessIntervalMillis()
.Se estiver fazendo trabalhos em segundo plano mais intensos repetidamente, como a pesquisa de dados meteorológicos, use
WorkManager
e envie atualizações ao bloco.Se a atualização for em resposta a um evento externo, como acender as luzes, receber um e-mail ou atualizar uma nota, envie uma mensagem do Firebase Cloud Messaging (FCM) para ativar o app novamente e enviar as atualizações ao bloco.
Se o processo de sincronização de dados de bloco for caro, faça o seguinte:
- Programe uma sincronização de dados.
- Inicie um timer de 1 a 2 segundos.
- Se você receber uma atualização de uma fonte de dados remota antes que o tempo acabe, mostre o valor atualizado da sincronização de dados. Caso contrário, mostre um valor local armazenado em cache.
Recomendados para você
- Observação: o texto do link aparece quando o JavaScript está desativado.
- Minimizar o efeito de atualizações regulares
- Acessar a localização em segundo plano
- Primeiros passos com o WorkManager