1. Antes de começar
Este codelab mostra o processo de criação de um widget de app para o SociaLite. Primeiro, você vai criar um widget simples do Resumo e adicionar ao SociaLite e à tela inicial. Depois, vai adicionar um estado zero ao widget usando componentes e um tema do Resumo. O codelab vai mostrar como oferecer suporte para uma interação do usuário e selecionar seu contato favorito no widget. Por fim, você vai aprender a atualizar o widget no seu app.
Pré-requisitos
- Conhecimentos básicos sobre Kotlin.
- Ter concluído o codelab Configurar o Android Studio ou ter familiaridade com o uso do Android Studio e teste de apps em um emulador do Android 15 ou em um dispositivo físico com Android 15.
- Conhecimentos básicos sobre o Hilt.
- Conhecimentos básicos sobre o Compose. O Resumo não usa combináveis do Jetpack Compose, mas sim a estrutura e o estilo de programação dele.
O que você vai aprender neste codelab
- Como configurar seu app para oferecer suporte a widgets.
- Como usar componentes do Resumo para criar um layout responsivo.
- Como usar
GlanceTheme
para oferecer suporte a cores dinâmicas nas telas iniciais dos seus usuários. - Como processar interações do usuário no seu widget.
- Como atualizar seu widget no app.
O que é necessário
- Ter a versão mais recente do Android Studio.
- Um dispositivo de teste ou emulador com o Android 12 ou versão mais recente.
- SDK do Android 12 ou versão mais recente.
2. Começar a configuração
Acessar o código inicial
- Se você tiver concluído os codelabs Processar restrições de ponta a ponta no Android 15 ou Adicionar animações de volta preditiva, siga para a seção Adicionar um Widget porque você já tem o código inicial.
- Faça o download do código inicial (link em inglês) no GitHub.
Ou então, você pode clonar o repositório e verificar a ramificação codelab_improve_android_experience_2024.
git clone git@github.com:android/socialite.git
cd socialite
git checkout codelab_improve_android_experience_2024
- Abra o SociaLite no Android Studio e execute o app no seu dispositivo ou emulador com Android 15. Uma tela parecida com esta vai aparecer:
SociaLite com navegação por gestos
3. Adicionar um widget
O que são widgets?
Um widget é uma parte do seu app que pode ser incorporada em outros apps Android. Geralmente, essa é a tela inicial do usuário.
Adicionar widgets ao app pode dar aos usuários a capacidade de iniciar rapidamente tarefas comuns, visualizar informações e personalizar o dispositivo com seu conteúdo.
O que é o Resumo?
O Resumo do Jetpack é uma biblioteca para criar widgets usando uma API do tipo Compose em Kotlin. Ele tem várias das mesmas vantagens do Compose, como recomposição, código de UI declarativo escrito em Kotlin e componentes opinativos. O Resumo elimina grande parte da necessidade de visualizações remotas de XML nos seus widgets.
Criar um widget
Os widgets no Android são declarados no AndroidManifest
como um elemento <receiver>
. Esse receiver precisa ser exportado, tratar o intent da ação android.appwidget.action.APPWIDGET_UPDATE
e fornecer um arquivo de configurações do widget do app por um elemento de metadados chamado android.appwidget.provider
.
Adicionar um widget ao SociaLite
Você precisa adicionar um widget ao Socialite que permita ao usuário ver o contato favorito e se há mensagens não lidas dessa pessoa. Se for o caso, tocar no widget deve levar o usuário ao chat do contato favorito. Além disso, use os componentes e temas do Resumo para garantir que o widget tenha a melhor aparência possível, usando um design responsivo e cores dinâmicas.
Para começar, adicione um widget estático “Hello World” ao Socialite. Depois disso, amplie os recursos do widget.
Para isso, faça o seguinte:
- Adicione as dependências do Resumo ao seu app.
- Crie uma implementação de
GlanceAppWidget
. - Crie um
GlanceAppWidgetReceiver
. - Configure seu widget com um arquivo XML de informações do widget do app.
- Adicione o receiver e as informações do widget do app ao arquivo
AndroidManifest.xml
.
Adicionar Resumo ao seu projeto
O código inicial adicionou as versões do Resumo e as coordenadas da biblioteca ao catálogo de versões do SociaLite: libs.versions.toml
.
libs.versions.toml
[versions]
//..
glance = "1.1.0-beta02"
[libraries]
glance-appwidget = { group = "androidx.glance", name = "glance-appwidget", version.ref = "glance" }
glance-material = { group = "androidx.glance", name = "glance-material3", version.ref = "glance" }
Além disso, as dependências do Resumo estão incluídas no arquivo app/build.gradle.kts
do SociaLite.
build.gradle.kts
dependencies {
...
implementation(libs.glance.appwidget)
implementation(libs.glance.material)
...
}
- Se você modificou esses arquivos, sincronize o projeto para baixar as bibliotecas do Resumo.
Criar o GlanceAppWidget
e o GlanceAppWidgetReceiver
O Android usa um broadcast receiver para alertar o SociaLite de que um widget foi adicionado, precisa ser atualizado ou foi removido. O Resumo fornece uma classe abstrata de receiver, GlanceAppWidgetReceiver, que estende AppWidgetProvider.
As implementações do GlanceAppWidgetReceiver
também são responsáveis por fornecer instâncias do GlanceAppWidget
. Essa classe renderiza os combináveis do Resumo em exibições remotas.
O código inicial inclui duas classes: SocialiteAppWidget
, que estende GlanceAppWidget
, e SocialiteAppWidgetReceiver
, que estende GlanceAppWidgetReceiver
.
Para começar, siga estas etapas:
- Navegue para o pacote
widget
emapp/src/main/java/com/google/android/samples/socialite/
. - Abra a classe
SociaLiteAppWidget
. Essa classe substitui o métodoprovideGlance
. - Substitua o
TODO
por uma chamada paraprovideContent
e transmita a função combinável do widget como um parâmetro. Por enquanto, o widget mostra apenas a mensagemHello World
, mas você vai adicionar mais funcionalidades mais tarde neste codelab.
package com.google.android.samples.socialite.widget
import android.content.Context
import androidx.glance.GlanceId
import androidx.glance.GlanceTheme
import androidx.glance.appwidget.GlanceAppWidget
import androidx.glance.appwidget.provideContent
import androidx.glance.text.Text
class SociaLiteAppWidget : GlanceAppWidget() {
override suspend fun provideGlance(context: Context, id: GlanceId) {
provideContent {
GlanceTheme {
Text("Hello World")
}
}
}
}
- Abra a classe
SociaLiteAppWidgetReceiver
no pacotewidget
. Por enquanto, o receiver fornece uma instância do seuSociaLiteWidget
, mas você vai adicionar mais funcionalidades em uma próxima seção. - Substitua o
TODO
pelo construtorSociaLiteAppWidget()
:
package com.google.android.samples.socialite.widget
import androidx.glance.appwidget.GlanceAppWidget
import androidx.glance.appwidget.GlanceAppWidgetReceiver
class SociaLiteAppWidgetReceiver : GlanceAppWidgetReceiver() {
override val glanceAppWidget: GlanceAppWidget = SociaLiteAppWidget()
}
Está tudo pronto para configurar o Android para mostrar seu widget e permitir que os usuários o adicionem na tela inicial.
Adicionar informações do provedor do app-widget
- Clique com o botão direito do mouse em res/xml > New > arquivo de recurso do XML.
- Digite socialite_widget_info como o nome do arquivo e appwidget-provider como o elemento raiz, depois clique em OK. Esse arquivo inclui os metadados do seu
appwidget
que é usado por umAppWidgetHost
para mostrar o widget. - Adicione o seguinte código ao arquivo socialite_widget_info.xml:
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:resizeMode="horizontal|vertical"
android:updatePeriodMillis="3600000"
android:minHeight="128dp"
android:minWidth="128dp"
android:minResizeHeight="128dp"
android:minResizeWidth="128dp"
android:configure="com.google.android.samples.socialite.widget.SociaLiteAppWidgetConfigActivity"
android:widgetFeatures="configuration_optional|reconfigurable"
android:previewImage="@drawable/widget_preview"
android:maxResizeHeight="512dp"
android:maxResizeWidth="512dp"
android:targetCellWidth="2"
android:targetCellHeight="2"
android:initialLayout="@layout/glance_default_loading_layout">
</appwidget-provider>
A tabela a seguir fornece uma visão geral dos atributos nesse código e descreve cada um deles:
Nome do atributo | Descrição |
| O widget pode ser redimensionado vertical e horizontalmente. |
| Especifique o tamanho padrão do widget quando adicionado à tela inicial. |
| Controla quando o host pode decidir atualizar o widget. O app pode atualizar o widget sempre que estiver em execução e tiver novas informações. |
| Define o tamanho para o qual você pode redimensionar o widget. |
| Especifique o tamanho mínimo padrão do widget quando adicionado à tela inicial. |
| Fornece um layout inicial que é mostrado enquanto o Resumo renderiza os elementos combináveis. |
| Fornece uma imagem estática do widget a ser mostrada no seletor de widgets. |
| Indique vários recursos que o widget suporta. Essas são dicas para o host do widget e não mudam de fato o comportamento dele. |
| O nome da classe da atividade de configuração. Essa é uma atividade que configura o widget posteriormente. |
Para saber quais são todos os atributos disponíveis, incluindo os recursos na API 31 ou mais recente, consulte AppWidgetProviderInfo
.
Atualizar AndroidManifest
e testar
Por fim, está tudo pronto para atualizar o arquivo AndroidManifest.xml
e testar seu widget. Defina um elemento receiver
como filho do elemento application
no arquivo. Esse receiver processa a intent APPWIDGET_UPDATE
e fornece seus metadados appwidget
para a tela de início do Android.
Para começar, siga estas etapas:
- Crie um elemento
receiver
para queSociaLiteAppWidgetReceiver
seja exportado. Copie e cole o seguinte no seu arquivoAndroidManifest.xml
depois do elementoapplication
:
<receiver
android:name=".widget.SociaLiteAppWidgetReceiver"
android:exported="true"
android:label="Favorite Contact">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/socialite_widget_info" />
</receiver>
- Compile e execute seu app.
- Quando o app estiver em execução, adicione o widget à tela inicial. Por exemplo, em um Pixel, toque e mantenha pressionado o plano de fundo, selecione Widgets > SociaLite. Você pode adicionar o widget à sua tela inicial.
O widget diz "Hello World" e tem um plano de fundo transparente. É evidente que esse não é o widget mais bonito nem o mais funcional até o momento. Na próxima seção, você vai adicionar um layout mais complicado e melhorar a aparência dele com um toque de cor do Material Design.
4. Melhorar o projeto
Agora você tem um widget estático, sem muitos recursos. Um bom widget faz o seguinte:
- Mantém a funcionalidade simples com conteúdo atualizado e curto.
- Minimiza falhas incômodas com um layout redimensionável.
- Aplica a cor do plano de fundo do host do widget do app.
Para uma discussão mais aprofundada sobre o que faz com que um widget seja bom, consulte Widgets.
Adicionar um Scaffold
Atualize seu widget para mostrar o componente Scaffold
do Resumo.
Scaffold
é fornecido pela biblioteca do Resumo. É uma API de slot simples para mostrar a interface de um widget com uma TitleBar
. Define a cor do plano de fundo como GlanceTheme.colors.widgetBackground
e aplica padding. Ele será seu componente de nível superior.
Para começar, siga estas etapas:
- Substitua sua implementação de
SociaLiteAppWidget
pelo seguinte código:
package com.google.android.samples.socialite.widget
import android.content.Context
import androidx.compose.runtime.Composable
import androidx.glance.GlanceId
import androidx.glance.GlanceModifier
import androidx.glance.GlanceTheme
import androidx.glance.ImageProvider
import androidx.glance.appwidget.GlanceAppWidget
import androidx.glance.appwidget.components.Scaffold
import androidx.glance.appwidget.components.TitleBar
import androidx.glance.appwidget.provideContent
import androidx.glance.layout.fillMaxSize
import androidx.glance.text.Text
import com.google.android.samples.socialite.R
class SociaLiteAppWidget : GlanceAppWidget() {
override suspend fun provideGlance(context: Context, id: GlanceId) {
provideContent {
GlanceTheme() {
Content()
}
}
}
@Composable
private fun Content() {
Scaffold(titleBar = {TitleBar(startIcon = ImageProvider(R.drawable.ic_launcher_monochrome), title = "SociaLite")},
modifier = GlanceModifier.fillMaxSize()) {
Text("Hello World")
}
}
}
- Para acessar suas atualizações, execute o app novamente e adicione uma nova cópia do widget à sua tela inicial.
Os widgets são visualizações remotas que são mostradas por um host externo. Depois, você vai adicionar a capacidade de atualizar automaticamente o widget dentro do app. Até lá, é preciso adicionar o widget do seletor para ver as mudanças de código.
Isso é muito melhor, mas quando você compara seu widget com outros, as cores parecem estar erradas. Nas telas iniciais, espera-se que os widgets definam suas cores com base nas configurações do tema do usuário. Com tokens de cores dinâmicas, você pode fazer com que o tema do widget se adapte ao plano de fundo e ao tema do seu dispositivo.
Adicionar cores dinâmicas
Adicione os tokens de cor widgetBackground
ao plano de fundo do scaffold e onSurface
ao texto da TitleBar
e componentes. Para atualizar o estilo do texto, é preciso importar a classe TextStyle
do Resumo. Para atualizar o plano de fundo do scaffold, defina a propriedade backgroundColor
de Scaffold
como GlanceTheme.colors.widgetBackground
.
Para começar, siga estas etapas:
- Inclua a nova importação no arquivo SociaLiteAppWidget.kt.
//Add to the imports section of your Kotlin code.
import androidx.glance.text.TextStyle
- Atualize o combinável
Content
para adicionarwidgetBackground
.
Scaffold(
titleBar = {
TitleBar(
textColor = GlanceTheme.colors.onSurface,
startIcon = ImageProvider(R.drawable.ic_launcher_monochrome),
title = "SociaLite",
)
},
backgroundColor = GlanceTheme.colors.widgetBackground,
modifier = GlanceModifier.fillMaxSize(),
) {
Text(text = "Hello World", style = TextStyle(color = GlanceTheme.colors.onSurface))
}
- Para acessar suas atualizações, execute o app novamente e adicione uma nova cópia do widget à sua tela inicial.
Ela combina com os temas de outros widgets na sua tela inicial e atualiza automaticamente as cores se você mudar o plano de fundo ou definir o modo escuro. Para um plano de fundo bem colorido, o widget se adapta à seção do plano de fundo em que se encontra.
|
|
Adicionar um estado zero
Agora você precisa pensar sobre o estado e configurar seu widget. Quando um widget é adicionado à tela inicial e requer configuração, geralmente é melhor mostrar uma mensagem estado zero. O estado zero solicita que o usuário configure o widget. Você adiciona uma atividade de configuração ao widget e o vincula ao estado zero.
Este codelab oferece aulas sobre como armazenar, acessar e modificar o estado de configuração de um widget. Você vai adicionar código para atualizar a interface do widget e exibir esse estado, além de criar uma ação lambda para processar as ações de toque do usuário.
Revisar o modelo do widget
Dedique um momento para revisar as classes no pacote com.google.android.samples.socialite.widget.model
.
Isso inclui as classes WidgetModel
, WidgetModelDao
e WidgetModelRepository
. Elas já estão presentes no código inicial do codelab e processam a persistência do estado dos widgets no banco de dados Room
subjacente. Além disso, essas classes usam o Hilt para gerenciar os ciclos de vida.
A classe WidgetModel
contém um widgetId
que é atribuído pelo Android, o contactId
do contato do SociaLite que ela exibe, um displayName
e photo
a serem mostrados e um booleano se o contato tiver mensagens não lidas. Eles são consumidos pelos combináveis SociaLiteAppWidget
e exibidos no widget.
WidgetModelDao
é um objeto de acesso a dados que resume o acesso ao banco de dados do SociaLite. WidgetModelRepository
fornece funções de conveniência para criar, ler, atualizar e excluir instâncias WidgetModel
. Essas classes são criadas pelo Hilt e injetadas no app com injeção de dependência.
- Abra o arquivo
WidgetModel.kt
no pacotemodel
encontrado emapp/src/main/java/com/google/android/samples/socialite/widget/model/
.
É uma classe data
com uma anotação Entity
. A cada instância do widget é atribuído um ID dedicado pelo Android, que é usado pelo SociaLite como uma chave primária para os dados do modelo. Cada instância do modelo monitora as informações básicas do contato associado e se há mensagens não lidas.
@Entity(
foreignKeys = [
ForeignKey(
entity = Contact::class,
parentColumns = ["id"],
childColumns = ["contactId"],
onDelete = ForeignKey.CASCADE,
),
],
indices = [
Index("widgetId"),
Index("contactId"),
],
)
data class WidgetModel(
@PrimaryKey val widgetId: Int,
val contactId: Long,
val displayName: String,
val photo: String,
val unreadMessages: Boolean = false,
) : WidgetState
O estado zero
Seu combinável Content
precisa carregar o modelo do widget a partir do WidgetModelRepository
e mostrar o estado zero se não houver nenhum modelo disponível. Caso contrário, ele vai exibir o conteúdo normal do widget. Por enquanto, esta será sua mensagem "Hello World", mas na próxima parte você vai criar uma interface melhor.
Substitua seu combinável Content
por uma expressão when
que exibe o combinável ZeroState
ou um marcador de posição Text
.
- No método
provideGlance
, fora do seu combinável, acesse uma referência aoWidgetModelRepository
e o ID atual do widget. Adicione as seguintes linhas antes deprovideContent
no métodoSociaLiteAppWidget
provideGlance
.
override suspend fun provideGlance(context: Context, id: GlanceId) {
val widgetId = GlanceAppWidgetManager(context).getAppWidgetId(id)
val repository = WidgetModelRepository.get(context)
Talvez também seja necessário adicionar as seguintes importações:
import com.google.android.samples.socialite.widget.model.WidgetModel
import com.google.android.samples.socialite.widget.model.WidgetModelRepository
import com.google.android.samples.socialite.widget.model.WidgetState.Loading
import androidx.glance.appwidget.GlanceAppWidgetManager
- Na função combinável
Content
, adicione o repositório e o ID do widget como parâmetros e use-os para carregar seu modelo. Atualize a assinatura da função do combinávelContent
e adicione a seguinte linha:
private fun Content(repository: WidgetModelRepository, widgetId: Int) {
val model = repository.loadModel(widgetId).collectAsState(Loading).value
- Se o Android Studio não adicionar a seguinte importação de maneira automática, faça isso manualmente:
import androidx.compose.runtime.collectAsState
Também será necessário atualizar provideGlance
para transmitir o ID e o repositório do widget para Content
.
Substitua provideGlance
pelo seguinte:
override suspend fun provideGlance(context: Context, id: GlanceId) {
val widgetId = GlanceAppWidgetManager(context).getAppWidgetId(id)
val repository = WidgetModelRepository.get(context)
provideContent {
GlanceTheme {
Content(repository, widgetId)
}
}
}
- Na função combinável
Content
, determine qual estado será mostrado caso exista um modelo. Transfira oScaffold
e o conteúdo do widget para o combinávelZeroState
substituindo o componenteScaffold
e o conteúdo dele por este:
when (model) {
is WidgetModel -> {Text("Hello World")}
else -> ZeroState(widgetId)
}
O combinável ZeroState
já está incluído no código inicial no pacote com.google.android.samples.socialite.widget.ui
.
- Se o Android Studio não importar automaticamente o pacote
com.google.android.samples.socialite.widget.ui
, adicione o seguinte código à seção de importação doSociaLiteAppWidget
.
import com.google.android.samples.socialite.widget.ui.ZeroState
- Para acessar suas atualizações, execute o app novamente e adicione uma nova cópia do widget à sua tela inicial. O widget vai exibir o componente ZeroState e um botão. O botão vai abrir a atividade de configuração quando você clicar nele e, na próxima seção, você vai atualizar o estado do widget dessa atividade.
A atividade da configuração
Revise a função combinável ZeroState. Essa função está no pacote com.google.android.samples.socialite.widget.ui
no arquivo ZeroState.kt
.
@Composable fun ZeroState(widgetId: Int) { val widgetIdKey = ActionParameters.Key<Int>(AppWidgetManager.EXTRA_APPWIDGET_ID) Scaffold( titleBar = { TitleBar( modifier = GlanceModifier.clickable(actionStartActivity(MainActivity::class.java)), textColor = GlanceTheme.colors.onSurface, startIcon = ImageProvider(R.drawable.ic_launcher_monochrome), title = "SociaLite", ) }, backgroundColor = GlanceTheme.colors.widgetBackground, modifier = GlanceModifier.fillMaxSize(), ) { Box(modifier = GlanceModifier.fillMaxSize(), contentAlignment = Alignment.Center) { Button( text = "Select Favorite Contact", onClick = actionStartActivity<SociaLiteAppWidgetConfigActivity>( parameters = actionParametersOf(widgetIdKey to widgetId), ), ) } } }
O combinável Scaffold
é transferido para o combinável ZeroState
. A TitleBar
tem o modificador clickable
, que abre a atividade principal do SociaLite. O ZeroState
usa o combinável Button
do Resumo para exibir uma call-to-action para o usuário. Quando clicada, abre a atividade SociaLiteAppWidgetConfigActivity
e inclui o ID do widget como uma intent extra. As duas ações usam a função de conveniência actionStartActivity
do Resumo. Para mais informações sobre ações, consulte Processar interação do usuário.
- Revise como
SociaLiteAppWidgetConfigActivity
é usada para atualizar a configuração do seu widget. Essa classe também é a atividade de configuração do seu widget. As atividades de configuração leem o número inteiro da intent extra com a chaveAppWidgetManager.
*EXTRA_APPWIDGET_ID.
*Para mais informações sobre as atividades de configuração, consulte Permitir que os usuários configurem widgets de apps. - Em
SociaLiteAppWidgetConfigActivity
, substituaTODO
na propriedadeContactRow
onClick
pelo seguinte código:
{
coroutineScope.launch {
widgetModelRepository.createOrUpdate(
WidgetModel(
appWidgetId,
contact.id,
contact.name,
contact.iconUri.toString(),
false,
),
)
SociaLiteAppWidget().updateAll(this@SociaLiteAppWidgetConfigActivity)
val resultValue = Intent().putExtra(
AppWidgetManager.EXTRA_APPWIDGET_ID,
appWidgetId,
)
setResult(RESULT_OK, resultValue)
finish()
}
}
Adicione o seguinte se o Android Studio não o fizer automaticamente
import com.google.android.samples.socialite.widget.model.WidgetModel
import androidx.glance.appwidget.updateAll
import kotlinx.coroutines.launch
Esse bloco de código atualiza o estado do seu widget. Primeiro, ele usa o repositório para salvar e atualizar o WidgetModel
com as informações do contato selecionado. A seguir, chama a função de suspensão updateAll
. Essa função atualiza todos os widgets na tela inicial e pode ser chamada de qualquer lugar do seu app. Por fim, esse bloco define o resultado da atividade de configuração para sinalizar que o widget foi atualizado.
- Execute e substitua o widget na tela inicial. O novo estado zero vai aparecer.
- Clique em Selecionar o contato favorito. Essa ação direciona você para a atividade de configuração.
- Selecione um contato. Essa ação atualiza seu widget. Porém, o widget ainda não mostra seu contato favorito porque você vai adicionar esse recurso na próxima seção.
Gerenciar os dados do widget
- Abra a ferramenta App inspection e conecte a um processo, se necessário. Selecione a guia Database inspector para ver o conteúdo do banco de dados do app.
- Selecione um contato favorito no widget e veja que ele atualiza como "Hello World." Voltando à ferramenta App inspection, a guia Widget model vai mostrar uma entrada para seu widget. Talvez seja necessário atualizar a tabela ou pressionar Live updates para ver as mudanças.
- Adicione outro widget e selecione outro contato. Talvez seja necessário pressionar Refresh table ou Live updates para mostrar o novo modelo.
- Remova o widget e observe que o modelo é deixado para trás no banco de dados depois que um widget é removido.
Você pode atualizar o SociaLiteAppWidgetReceiver
para limpar o banco de dados quando um widget é removido substituindo onDeleted
.
Para limpar os modelos de widgets órfãos, chame WidgetModelRepository.cleanupWidgetModels
. A classe do repositório é gerenciada pelo Hilt e é preciso usar a injeção de dependência para acessar a instância dela.
- Em
SociaLiteAppWidgetReceiver
, adicione a anotação HiltAndroidEntryPoint
à sua declaração de classe do receiver e injete a instânciaWidgetModelRepository
. - Chame
WidgetModelRepository.cleanupWidgetModels
na substituição do método poronDeleted
.
O código ficará assim:
package com.google.android.samples.socialite.widget
import android.content.Context
import androidx.glance.appwidget.GlanceAppWidget
import androidx.glance.appwidget.GlanceAppWidgetReceiver
import com.google.android.samples.socialite.widget.model.WidgetModelRepository
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
@AndroidEntryPoint
class SociaLiteAppWidgetReceiver : GlanceAppWidgetReceiver() {
override val glanceAppWidget: GlanceAppWidget = SociaLiteAppWidget()
@Inject
lateinit var repository: WidgetModelRepository
override fun onDeleted(context: Context, appWidgetIds: IntArray) {
super.onDeleted(context, appWidgetIds)
repository.cleanupWidgetModels(context)
}
}
- Execute o app de novo. Veja que a linha de modelo é removida no App inspector quando o widget é removido da tela inicial.
5. Adicionar a UI do contato e atualizar quando novas mensagens chegarem
Você chegou à parte final do codelab. Nesta seção, você implementa a interface final do contato para o widget e a atualiza quando há uma mensagem não lida para o contato.
- Revise sua classe
WidgetModelRepository
no pacote do modelo.
Esse é o método de conveniência updateUnreadMessagesForContact
. Ele atualiza widgets associados com o ID de um contato.
//Don't add this code.
fun updateUnreadMessagesForContact(contactId: Long, unread: Boolean) {
coroutineScope.launch {
widgetModelDao.modelsForContact(contactId).filterNotNull().forEach { model ->
widgetModelDao.update(
WidgetModel(model.widgetId, model.contactId, model.displayName, model.photo, unread)
)
SociaLiteAppWidget().updateAll(appContext)
}
}
}
Esse método tem dois parâmetros: contactId
, o ID do contato que está sendo atualizado e unread
, um booleano do estado da mensagem não lida. Esse método usa WidgetModelDao
, para encontrar todos os modelos de widget que mostram esse contato e atualizar o modelo com o novo estado. Então, a função chama o método SociaLiteAppWidget().updateAll
fornecido pelo Resumo para atualizar todos os widgets na tela inicial do usuário.
Agora que você entende como um widget e seu estado são atualizados, pode criar sua UI de contato, enviar uma mensagem e vê-la ser atualizada. Para isso, atualize o SociaLiteAppWidget
com um FavoriteContact
combinável no layout do widget. Nesse layout, verifique também se vai mostrar No new messages
ou New Messages!
.
- Revise o arquivo
FavoriteContact.kt
no pacotecom.google.android.samples.socialite.widget.ui
.
//Don't add this code.
@Composable
fun FavoriteContact(model: WidgetModel, onClick: Action) {
Column(
modifier = GlanceModifier.fillMaxSize().clickable(onClick)
.background(GlanceTheme.colors.widgetBackground).appWidgetBackground()
.padding(bottom = 8.dp),
verticalAlignment = Alignment.Vertical.Bottom,
horizontalAlignment = Alignment.Horizontal.CenterHorizontally,
) {
Image(
modifier = GlanceModifier.fillMaxWidth().wrapContentHeight().defaultWeight()
.cornerRadius(16.dp),
provider = ImageProvider(model.photo.toUri()),
contentScale = ContentScale.Crop,
contentDescription = model.displayName,
)
Column(
modifier = GlanceModifier.fillMaxWidth().wrapContentHeight().padding(top = 4.dp),
verticalAlignment = Alignment.Vertical.Bottom,
horizontalAlignment = Alignment.Horizontal.CenterHorizontally,
) {
Text(
text = model.displayName,
style = TextStyle(
fontWeight = FontWeight.Bold,
fontSize = 24.sp,
color = (GlanceTheme.colors.onSurface),
),
)
Text(
text = if (model.unreadMessages) "New Message!" else "No messages",
style = TextStyle(
fontWeight = FontWeight.Bold,
fontSize = 16.sp,
color = (GlanceTheme.colors.onSurface),
),
)
}
}
}
- Substitua
Text("Hello World")
noContent
combinável doSociaLiteAppWidget
por uma chamada para oFavoriteContact
combinável.
Esse combinável terá o WidgetModel e uma ação criada pela função actionStartActivity
do Resumo.
- Adicione a chamada para o bloco
when
antes doZeroState
quando o modelo não forWidgetModel
.
when (model) {
is WidgetModel -> FavoriteContact(model = model, onClick = actionStartActivity(
Intent(LocalContext.current.applicationContext, MainActivity::class.java)
.setAction(Intent.ACTION_VIEW)
.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
.setData("https://socialite.google.com/chat/${model.contactId}".toUri()))
)
else -> ZeroState(widgetId)
}
- Se o Android Studio não adicionar automaticamente as seguintes importações, faça isso agora:
import com.google.android.samples.socialite.widget.ui.FavoriteContact
import androidx.glance.appwidget.action.actionStartActivity
import android.content.Intent
import com.google.android.samples.socialite.MainActivity
import androidx.core.net.toUri
- Execute o app.
- Selecione um contato favorito, envie uma mensagem e saia imediatamente do app antes da resposta. Quando ela chegar, o estado do widget vai mudar.
- Clique no widget para abrir o chat e ver que o estado foi atualizado novamente quando você sair para a tela principal.
6. Parabéns
Você concluiu o codelab e aprendeu a criar um widget usando o Resumo! Você vai se sentir à vontade para criar um widget bonito que fique bem em muitas telas iniciais, processe a entrada do usuário e se atualize.
Para acessar o código da solução na ramificação main
, siga estas etapas:
- Se você já baixou o SocialLite, execute este comando:
git checkout main
- Caso contrário, baixe o código de novo para visualizar a ramificação
main
:
git clone git@github.com:android/socialite.git