On this page
Widgets run inside the launcher process, not your app, so they use RemoteViews under the hood. Glance hides that complexity behind composable-style functions, but its components are separate from regular Compose UI, so not every Compose API works in a widget.
How a Glance widget works
Build a widget with Glance
dependencies {
implementation("androidx.glance:glance-appwidget:1.1.1") // check for the latest stable version
implementation("androidx.glance:glance-material3:1.1.1")
}class TasksWidget : GlanceAppWidget() {
override suspend fun provideGlance(context: Context, id: GlanceId) {
val tasks = TaskRepository.get(context).todayTasks() // load data (suspend)
provideContent {
GlanceTheme {
Column(
modifier = GlanceModifier.fillMaxSize()
.background(GlanceTheme.colors.background)
.padding(12.dp)
.clickable(actionStartActivity<MainActivity>()),
) {
Text("Today (${tasks.size})", style = TextStyle(fontWeight = FontWeight.Bold))
tasks.take(3).forEach { Text("โข ${it.title}", maxLines = 1) }
}
}
}
}
}
class TasksWidgetReceiver : GlanceAppWidgetReceiver() {
override val glanceAppWidget: GlanceAppWidget = TasksWidget()
}Note the imports: androidx.glance.layout.Column and androidx.glance.text.Text, not the Compose UI versions.
Register the widget
<receiver android:name=".TasksWidgetReceiver" android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="@xml/tasks_widget_info" />
</receiver>
<!-- res/xml/tasks_widget_info.xml -->
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="180dp" android:minHeight="110dp"
android:targetCellWidth="3" android:targetCellHeight="2"
android:resizeMode="horizontal|vertical"
android:updatePeriodMillis="0"
android:initialLayout="@layout/glance_default_loading_layout"
android:description="@string/tasks_widget_description"
android:widgetCategory="home_screen" />Updating the widget
// After data changes in the app
suspend fun refreshWidgets(context: Context) {
TasksWidget().updateAll(context)
}
// Periodically (minimum 15 min) with WorkManager
class WidgetRefreshWorker(ctx: Context, p: WorkerParameters) : CoroutineWorker(ctx, p) {
override suspend fun doWork(): Result {
TasksWidget().updateAll(applicationContext)
return Result.success()
}
}Avoid frequent updatePeriodMillis updates: they wake the device and drain battery. See WorkManager.
App shortcuts
Shortcuts appear on long-press of the launcher icon. Use static shortcuts (XML) for core actions, dynamic ones for context-dependent actions, and pinned ones that the user adds to the home screen.
val shortcut = ShortcutInfoCompat.Builder(context, "new_task")
.setShortLabel("New task")
.setLongLabel("Create a new task")
.setIcon(IconCompat.createWithResource(context, R.drawable.ic_add))
.setIntent(Intent(Intent.ACTION_VIEW, Uri.parse("https://example.com/tasks/new"),
context, MainActivity::class.java))
.build()
ShortcutManagerCompat.pushDynamicShortcut(context, shortcut)Route shortcut intents through the same navigation as deep links.
Best practices
- Design for multiple sizes, and use
SizeMode.ResponsiveorSizeMode.Exactto adapt layouts. - Support dynamic colour with
GlanceTheme. - Keep widgets glanceable: one purpose, a little key data, and a clear tap target.
- Provide preview images or generated previews so the widget picker looks good.
- Keep shortcut counts small (four or so are typically shown).
Troubleshooting
- Widget shows "Can't load widget": an exception in
provideGlance, or an unsupported composable. Check Logcat. - Widget not updating: call
update/updateAllafter data changes, and check that the work actually runs. - Clicks do nothing: use Glance actions (
actionStartActivity,actionRunCallback), not Composeclickablelambdas.
Frequently asked questions
Can I use regular Compose in a widget?
No. Glance provides its own composables that map to RemoteViews. The programming model is similar, but the components differ.
Can widgets show lists?
Yes. Glance offers LazyColumn for widgets, backed by RemoteViews collections.
Conclusion
Use Glance for widgets with a Compose-like API, push updates when data changes (or with WorkManager), keep widgets glanceable and responsive, and add shortcuts for key actions routed through your navigation.
Next step: build for the wrist with Wear OS App Development.
Official references
๐ฑ Apps built by Yunok Tech
Real Android apps on Google Play, free to download.
Walzi4K wallpapers for lock and home screenGet it โธ
NotiVaultNotification history: recover dismissed notificationsGet it โธ
Ready to build real Android applications?
Jetpack Compose clicks once you build real screens with real state. Practise modern Android UI development on projects that go beyond toy examples.
Move beyond theory and strengthen your Android development skills with Yunoktech's Android course. Learn core concepts, practical implementation, modern Android development techniques, and the reasoning behind building maintainable applications.
Explore the Android course and take your next step as an Android developer.