1. Antes de comenzar
En este codelab, aprenderás el proceso de crear un widget de app para SociaLite. Primero, crearás un widget simple de Glance y lo agregarás a SociaLite y a la pantalla principal. Luego, agregarás al widget un estado cero usando componentes y un tema de Glance. A continuación, en el codelab se explicará cómo brindar compatibilidad con una interacción del usuario para seleccionar el contacto favorito desde el widget. Por último, aprenderás a actualizar el widget desde tu app.
Requisitos previos
- Conocimientos básicos de Kotlin
- Haber completado el codelab sobre configuración de Android Studio o saber cómo usar Android Studio y probar apps en un emulador de Android 15 o un dispositivo físico que ejecute Android 15
- Conocimientos básicos de Hilt
- Conocimientos básicos de Compose (Glance no usa funciones de componibilidad de Jetpack Compose, pero sí reutiliza el framework y el estilo de programación)
Qué aprenderás en este codelab
- Cómo configurar tu app para que sea compatible con los widgets
- Cómo usar componentes de Glance para crear un diseño responsivo
- Cómo usar
GlanceThemepara admitir colores dinámicos en las pantallas principales de los usuarios - Cómo controlar las interacciones del usuario en tu widget
- Cómo actualizar tu widget desde la app
Requisitos
- La versión más reciente de Android Studio
- Un dispositivo de prueba o un emulador que ejecuten Android 12 o una versión posterior
- El SDK de Android 12 o una versión posterior

2. Prepárate
Obtén el código de partida
- Si ya completaste los codelabs "Cómo cumplir con los requisitos de borde a borde de Android 15" o "Cómo agregar animaciones del gesto atrás predictivo", avanza a la sección Agrega un widget porque ya tienes el código de partida.
- Descarga el código de partida de GitHub.
También puedes clonar el repositorio y consultar la rama codelab_improve_android_experience_2024.
git clone git@github.com:android/socialite.git
cd socialite
git checkout codelab_improve_android_experience_2024
- Abre SociaLite en Android Studio y ejecuta la app en tu dispositivo o emulador con Android 15. Verás una pantalla como la siguiente:

SociaLite con navegación por gestos
3. Agrega un widget
¿Qué son los widgets?
Un widget es una parte de tu app que se puede incorporar en otras apps para Android. Con mayor frecuencia, se trata de la pantalla principal del usuario.
Al agregar widgets a tu app, los usuarios pueden iniciar tareas comunes rápidamente, ver información de un vistazo y personalizar su dispositivo con tu contenido.
¿Qué es Glance?
Jetpack Glance es una biblioteca para escribir widgets usando una API similar a la de Compose en Kotlin. Tiene varias ventajas de Compose, como la recomposición, el código declarativo de la IU escrito en Kotlin y los componentes definidos. Glance elimina gran parte de la necesidad de usar vistas remotas XML en tus widgets.
Crea un widget
Los widgets en Android se declaran en el AndroidManifest como un elemento <receiver>. Este receptor debe exportarse, controlar el intent de acción android.appwidget.action.APPWIDGET_UPDATE y proporcionar un archivo de configuración del widget de la app a través de un elemento de metadatos llamado android.appwidget.provider.
Agrega un widget a SociaLite

Te recomendamos que agregues un widget a SociaLite que les permita a los usuarios ver su contacto favorito y si tienen mensajes no leídos de esa persona. Si es así, al presionar el widget, el usuario debería poder chatear con su contacto favorito. Además, puedes utilizar componentes y temas de Glance para asegurarte de que tu widget se vea de manera óptima con un diseño responsivo y color dinámico.
Para comenzar, agregarás un widget estático "Hello World" a SociaLite. Luego, ampliarás las capacidades del widget.
Para ello, haz lo siguiente:
- Agrega las dependencias de Glance a tu app.
- Crea una implementación de
GlanceAppWidget. - Crea un
GlanceAppWidgetReceiver. - Configura el widget con un archivo en formato XML de información sobre el widget de la app.
- Agrega el receptor y la información sobre el widget de la app al archivo
AndroidManifest.xml.
Agrega Glance a tu proyecto
El código de partida agregó las versiones de Glance y las coordenadas de la biblioteca al catálogo de versiones de SociaLite: libs.versions.toml.
libs.versions.toml
[versions]
//..
glance = "1.1.1"
[libraries]
glance-appwidget = { group = "androidx.glance", name = "glance-appwidget", version.ref = "glance" }
glance-material = { group = "androidx.glance", name = "glance-material3", version.ref = "glance" }
Además, se incluyeron las dependencias de Glance en el archivo app/build.gradle.kts de SociaLite.
build.gradle.kts
dependencies {
...
implementation(libs.glance.appwidget)
implementation(libs.glance.material)
...
}
- Si modificaste estos archivos, sincroniza el proyecto para descargar las bibliotecas de Glance.
Crea tu GlanceAppWidget y GlanceAppWidgetReceiver
Android usa un receptor de transmisiones para alertar a SociaLite que un widget se agregó, se debe actualizar o se quitó. Glance proporciona una clase de receptor abstracta, GlanceAppWidgetReceiver, que extiende AppWidgetProvider.
Las implementaciones de GlanceAppWidgetReceiver también son responsables de proporcionar instancias de GlanceAppWidget. Esta clase renderiza las funciones de componibilidad de Glance en vistas remotas.
El código de partida incluye dos clases: SocialiteAppWidget, que extiende GlanceAppWidget, y SocialiteAppWidgetReceiver, que extiende GlanceAppWidgetReceiver.
Para comenzar, sigue estos pasos:
- Navega al paquete
widgetenapp/src/main/java/com/google/android/samples/socialite/. - Abre la clase
SociaLiteAppWidget. Esta clase anula el métodoprovideGlance. - Reemplaza
TODOpor una llamada aprovideContenty pasa la función de componibilidad de tu widget como un parámetro. Por ahora, el widget solo muestra el mensajeHello World, pero agregarás otras funciones más adelante en este 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")
}
}
}
}
- Abre la clase
SociaLiteAppWidgetReceiveren el paquetewidget. Por ahora, el receptor proporciona una instancia de tuSociaLiteWidget, pero agregarás otras funciones en una sección más adelante. - Reemplaza
TODOpor el constructorSociaLiteAppWidget():
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()
}
Ya está todo listo para configurar Android para que muestre tu widget y les permita a los usuarios agregarlo a la pantalla principal.
Agrega información de proveedor de app-widget
- Haz clic con el botón derecho en **
res/xml** > New > XML resource file. - Ingresa
socialite_widget_infocomo el nombre del archivo yappwidget-providercomo el elemento raíz. Luego, haz clic en OK. Este archivo incluye los metadatos de tuappwidgetque utiliza unAppWidgetHostpara mostrar el widget al principio. - Agrega el siguiente código al archivo
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>
En la siguiente tabla, se proporciona una descripción general de los atributos en este código y se detalla cada uno de ellos:
Nombre del atributo | Descripción |
| El widget puede cambiar de tamaño vertical y horizontalmente. |
| Especifica el tamaño predeterminado del widget cuando se agregue a la pantalla principal. |
| Controla cuándo el host del widget podría decidir actualizarlo. Tu app puede actualizar el widget cuando se esté ejecutando y tenga información nueva para mostrar. |
| Establece el tamaño mínimo del widget. |
| Especifica el tamaño mínimo predeterminado del widget cuando se agrega a la pantalla principal. |
| Proporciona un diseño inicial que se muestra mientras Glance renderiza las funciones de componibilidad. |
| Proporciona una imagen estática del widget que se mostrará en el selector. |
| Indica las diferentes funciones que admite el widget. Son sugerencias para el host y no cambian el comportamiento del widget. |
| El nombre de la clase de actividad de configuración. Se trata de una actividad que configura el widget más adelante. |
Para ver todos los atributos disponibles, incluidas las funciones de la API 31 o posterior, consulta AppWidgetProviderInfo.
Actualiza AndroidManifest y realiza pruebas
Ya tienes todo listo para actualizar el archivo AndroidManifest.xml y probar tu widget. Define un receiver como elemento secundario del elemento application en el archivo. Este receptor controla el intent APPWIDGET_UPDATE y le brinda metadatos de tu appwidget al Launcher de Android.
Para comenzar, sigue estos pasos:
- Crea un elemento
receiverparaSociaLiteAppWidgetReceiverpara que se exporte. Copia y pega lo siguiente en el archivoAndroidManifest.xmldespués del 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>
- Compila y ejecuta tu app.
- Con la app en ejecución, agrega el widget a tu pantalla principal. Por ejemplo, en un dispositivo Pixel, mantén presionado el fondo y selecciona Widgets > SociaLite. Deberías poder agregar tu widget a la pantalla principal.

El widget dice "Hello World" y tiene un fondo transparente. Claro que aún no tiene el mejor aspecto ni es el más funcional. En la siguiente sección, agregarás un diseño más complicado y embellecerás el widget con un toque de color de Material Design.
4. Mejora el diseño
Ahora tienes un widget estático al que le faltan muchas de las funciones que conforman un widget útil. Un widget útil realiza lo siguiente:
- Mantiene el contenido breve y actual, y la funcionalidad simple.
- Minimiza los espacios raros con un diseño que se puede cambiar de tamaño.
- Aplica color a partir del fondo del host del widget de la app.
Consulta un análisis más detallado de qué factores conforman un buen widget en Widgets.
Agrega andamiaje
Ahora actualizarás el widget para que muestre el componente Scaffold de Glance.
La biblioteca de Glance proporciona Scaffold. Es una API de ranuras simple para mostrar la IU de un widget con una TitleBar. Establece el color de fondo en GlanceTheme.colors.widgetBackground y aplica padding. Será tu componente de nivel superior.
Para comenzar, sigue estos pasos:
- Reemplaza tu implementación de
SociaLiteAppWidgetpor el siguiente 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 ver tus actualizaciones, vuelve a ejecutar la app y agrega una nueva copia del widget a la pantalla principal.

Recuerda que los widgets son vistas remotas que muestra un host externo. Más adelante, agregarás la habilidad de actualizar automáticamente el widget dentro de la app. Hasta entonces, deberás agregar el widget desde el selector para ver los cambios del código.
Como ves, ha mejorado mucho. Sin embargo, cuando lo comparas con otros widgets, los colores no parecen adecuados. En las pantallas principales, se espera que los widgets establezcan sus colores en función del tema elegido por el usuario. Los tokens de color dinámico permiten que el tema de tu widget se adapte al fondo de pantalla y al tema de tu dispositivo.
Agrega color dinámico
Ahora agregarás el token de color widgetBackground al fondo del andamiaje y los tokens de color onSurface al texto de TitleBar y los componentes Text. Para actualizar el estilo del texto, debes importar la clase TextStyle de Glance. Para actualizar el fondo del andamiaje, configura la propiedad backgroundColor de Scaffold en GlanceTheme.colors.widgetBackground.
Para comenzar, sigue estos pasos:
- Incluye la nueva importación en el archivo
SociaLiteAppWidget.kt.
//Add to the imports section of your Kotlin code.
import androidx.glance.text.TextStyle
- Actualiza tu función de componibilidad
Contentpara agregarwidgetBackground.
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 ver tus actualizaciones, vuelve a ejecutar la app y agrega una nueva copia del widget a la pantalla principal.
Coincide con los temas de otros widgets en la pantalla principal y actualiza automáticamente los colores si cambias el fondo o estableces el modo oscuro. Si quieres un fondo muy colorido, el widget se adaptará a la sección del fondo donde se ubica.
|
|
Agrega un estado cero
Ahora debes dedicarte al estado y la configuración de tu widget. Cuando se agrega un widget a la pantalla principal y requiere configuración, lo mejor suele ser mostrar un estado cero. El estado cero le indica al usuario que configure el widget. Agregas una actividad de configuración a tu widget y creas un vínculo a ella desde el estado cero.
Este codelab proporciona clases para almacenar el estado de configuración de un widget, acceder a él y modificarlo. Agregarás código para actualizar la IU de tu widget de modo que muestre este estado, y crearás una acción de lambda para controlar las acciones de presión de un usuario.
Revisa el modelo del widget
Dedica un momento a revisar las clases del paquete com.google.android.samples.socialite.widget.model.
Esto incluye la clase WidgetModel y las clases WidgetModelDao y WidgetModelRepository. Estas clases ya están presentes en el código de partida del codelab y se encargan de conservar el estado de los widgets en la base de datos subyacente de Room. Además, estas clases emplean Hilt para administrar sus ciclos de vida.
La clase WidgetModel contiene un widgetId que asigna Android, el contactId del contacto de SociaLite que muestra, un displayName y una photo que se mostrarán, y un booleano si el contacto tiene mensajes no leídos. Las funciones de componibilidad de SociaLiteAppWidget los consumen y se muestran en el widget.
WidgetModelDao es un objeto de acceso a datos que abstrae el acceso a la base de datos de SociaLite. WidgetModelRepository proporciona funciones útiles para crear, leer, actualizar y borrar instancias de WidgetModel. Hilt crea estas clases, que se insertan en la app con la inserción de dependencias.
- Abre el archivo
WidgetModel.kten el paquetemodelque se encuentra enapp/src/main/java/com/google/android/samples/socialite/widget/model/.
Es una clase data con una anotación Entity. Android asigna un ID dedicado a cada instancia del widget, y SociaLite utiliza este ID como clave primaria para los datos del modelo. Cada instancia del modelo registra la información básica del contacto asociado y si hay mensajes no leídos de ese contacto.
@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
El estado cero
Te recomendamos que, si no hay ningún modelo disponible, tu función de componibilidad Content cargue el modelo del widget desde el WidgetModelRepository y muestre el estado cero; de lo contrario, te recomendamos mostrar el contenido normal de tu widget. Por ahora, este será tu mensaje "Hello World", pero en la próxima sección, crearás una interfaz mejor.
Reemplazarás tu función de componibilidad Content por una expresión when que muestre la función de componibilidad ZeroState o un marcador de posición Text.
- En el método
provideGlance, fuera de la función de componibilidad, obtén una referencia alWidgetModelRepositoryy el ID de widget actual. Agrega las siguientes líneas antes deprovideContenten el métodoSociaLiteAppWidgetprovideGlance.
override suspend fun provideGlance(context: Context, id: GlanceId) {
val widgetId = GlanceAppWidgetManager(context).getAppWidgetId(id)
val repository = WidgetModelRepository.get(context)
Es posible que también debas agregar estas importaciones:
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
- En la función de componibilidad
Content, agrega el ID de widget y repositorio como parámetros, y utilízalos para cargar tu modelo. Actualiza la firma de la función de componibilidadContenty agrega la siguiente línea:
private fun Content(repository: WidgetModelRepository, widgetId: Int) {
val model = repository.loadModel(widgetId).collectAsState(Loading).value
- Si Android Studio no agrega la siguiente importación automáticamente, agrégala de forma manual:
import androidx.compose.runtime.collectAsState
También deberás actualizar provideGlance para pasar el ID de widget y repositorio a Content.
Reemplaza provideGlance por lo siguiente:
override suspend fun provideGlance(context: Context, id: GlanceId) {
val widgetId = GlanceAppWidgetManager(context).getAppWidgetId(id)
val repository = WidgetModelRepository.get(context)
provideContent {
GlanceTheme {
Content(repository, widgetId)
}
}
}
- En tu función de componibilidad
Content, determina qué estado mostrar en función de si existe un modelo. Mueve elScaffoldy el contenido del widget a la función de componibilidadZeroStatereemplazando el componenteScaffoldy su contenido por lo siguiente en un bloque:
when (model) {
is WidgetModel -> {Text("Hello World")}
else -> ZeroState(widgetId)
}
La función de componibilidad ZeroState ya está incluida en el código de partida en el paquete com.google.android.samples.socialite.widget.ui.
- Si Android Studio no importó automáticamente el paquete
com.google.android.samples.socialite.widget.ui, agrega el siguiente código a la sección de importaciones deSociaLiteAppWidget.
import com.google.android.samples.socialite.widget.ui.ZeroState
- Para ver tus actualizaciones, vuelve a ejecutar la app y agrega una nueva copia del widget a la pantalla principal. Verás que el widget muestra el componente ZeroState y un botón. El botón abrirá la actividad de configuración cuando hagas clic en él, y, en la siguiente sección, actualizarás el estado de tu widget a partir de esta actividad.
|
|
La actividad de configuración
Revisa la función de componibilidad ZeroState. Esta función se encuentra en el paquete com.google.android.samples.socialite.widget.ui en el archivo 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),
),
)
}
}
}
La función de componibilidad Scaffold se mueve a la función de componibilidad ZeroState. TitleBar tiene el modificador clickable, que abre la actividad principal de SociaLite. Tu ZeroState usa la función de componibilidad Button de Glance para mostrar un llamado a la acción al usuario y, cuando hace clic en él, abre la actividad SociaLiteAppWidgetConfigActivity e incluye el ID de widget como extra de intent. Ambas acciones usan la función útil actionStartActivity de Glance. Para obtener más información sobre las acciones, consulta Controla la interacción del usuario.
- Revisa cómo se usa
SociaLiteAppWidgetConfigActivitypara actualizar la configuración de tu widget. Esta clase también es la actividad de configuración para tu widget. Las actividades de configuración leen el extra de número entero de intent con la claveAppWidgetManager.*EXTRA_APPWIDGET_ID.* Para obtener más información sobre las actividades de configuración, consulta Permite que los usuarios configuren widgets de apps. - En
SociaLiteAppWidgetConfigActivity, reemplazaTODOen la propiedadContactRowonClickpor el siguiente 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()
}
}
Agrega las siguientes inclusiones si Android Studio no lo hace automáticamente
import com.google.android.samples.socialite.widget.model.WidgetModel
import androidx.glance.appwidget.updateAll
import kotlinx.coroutines.launch
Este bloque de código actualiza el estado de tu widget. Primero, usa el repositorio para guardar o actualizar el WidgetModel con la información del contacto seleccionado. Luego, llama a la función de suspensión updateAll. Esta función actualiza todos los widgets en la pantalla principal, y se la puede llamar desde cualquier parte de tu app. Por último, el bloque establece el resultado de la actividad de configuración para indicar que actualizó el widget correctamente.
- Ejecuta y reemplaza tu widget en la pantalla principal. Deberías ver el nuevo estado cero.

- Haz clic en Seleccionar contacto favorito. Esto te lleva a la actividad de configuración.

- Selecciona un contacto. Esto actualiza tu widget. Sin embargo, el widget aún no muestra tu contacto favorito porque agregarás esa capacidad en la siguiente sección.
Administra los datos del widget
- Abre la herramienta App inspection, conéctate a un proceso si es necesario y selecciona la pestaña Inspector de bases de datos para observar el contenido de la base de datos de la app.
- Selecciona un contacto favorito en el widget y comprueba si se actualiza a "Hello World". De regreso en la herramienta de inspección de apps, deberías ver una pestaña Widget model con una entrada para tu widget. Tal vez debas actualizar la tabla o presionar Live updates para ver los cambios.

- Agrega otro widget y selecciona otro contacto. Tal vez debas presionar Refresh table o Live updates para ver el modelo nuevo.
- Quita el widget y comprueba que el modelo queda en la base de datos después de quitarlo.
Para actualizar SociaLiteAppWidgetReceiver y limpiar tu base de datos cuando se quita un widget, anula onDeleted.
Para limpiar modelos de widget huérfanos, puedes llamar a WidgetModelRepository.cleanupWidgetModels. Hilt administra la clase de repositorio, y debes usar la inserción de dependencias para acceder a su instancia.
- En
SociaLiteAppWidgetReceiver, agrega la anotaciónAndroidEntryPointde Hilt a tu declaración de clase de receptor e inserta la instancia deWidgetModelRepository. - Llama a
WidgetModelRepository.cleanupWidgetModelsen la anulación de método paraonDeleted.
Tu código debería verse de la siguiente manera:
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)
}
}
- Vuelve a ejecutar la app. Deberías ver que la fila del modelo se quita del inspector de apps cuando se quita el widget de la pantalla principal.
5. Agrega la IU de contactos y actualízala cuando lleguen nuevos mensajes
Estás en la recta final del codelab. En esta sección, implementarás la IU de contactos final para el widget y la actualizarás cuando se reciba un mensaje no leído del contacto.
- Revisa la clase
WidgetModelRepositoryen el paquetemodel.
Aquí es donde tienes el método útil updateUnreadMessagesForContact; actualiza los widgets asociados con el ID de un contacto.
//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)
}
}
}
Este método tiene dos parámetros: contactId, el ID del contacto que se actualizará, y unread, un booleano del estado del mensaje no leído. Este método usa WidgetModelDao para encontrar todos los modelos de widget que muestran este contacto y actualizan el modelo con el nuevo estado de leído. Luego, la función llama al método SociaLiteAppWidget().updateAll que proporcionó Glance para actualizar todos los widgets en la pantalla principal del usuario.
Ahora que sabes cómo se actualizan los widgets y su estado, puedes crear tu IU de contacto, enviar un mensaje y ver cómo se actualiza. Para ello, actualiza SociaLiteAppWidget con una función de componibilidad FavoriteContact en el diseño de tu widget. En este diseño, también comprueba si deberías mostrar No new messages o New Messages!.
- Revisa el archivo
FavoriteContact.kten el paquetecom.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),
),
)
}
}
}
- Reemplaza
Text("Hello World")en la función de componibilidadContentdeSociaLiteAppWidgetpor una llamada tu función de componibilidadFavoriteContact.
Esta función de componibilidad tomará el WidgetModel y una Action creada por la función actionStartActivity de Glance.
- Agrega la llamada a tu bloque
whenantes deZeroStatecuando el modelo no seaWidgetModel.
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)
}
- Si Android Studio no agrega automáticamente las siguientes importaciones, hazlo ahora:
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
- Ejecuta tu app.
- Selecciona un contacto favorito, envía un mensaje y cierra la app de inmediato antes de que el contacto responda. El estado del widget debería cambiar cuando llegue la respuesta.
- Haz clic en el widget para abrir el chat y comprueba que el estado se haya vuelto a actualizar cuando regreses a la pantalla principal.

6. Felicitaciones
Completaste correctamente el codelab y aprendiste a escribir un widget con Glance. Ya tienes todas las herramientas para crear un widget atractivo que se vea bien en muchas pantallas principales, controle las entradas del usuario y se actualice solo.
Para obtener el código de la solución en la rama main, sigue estos pasos:
- Si ya descargaste SociaLite, ejecuta este comando:
git checkout main
- De lo contrario, vuelve a descargar el código para ver la rama
main:
git clone git@github.com:android/socialite.git
Pantalla principal con un tema claro
Pantalla principal con un tema oscuro