Android setup¶
- Add Glance to your app module (the library itself does not depend on it):
implementation("androidx.glance:glance-appwidget:1.1.1") - Declare a receiver and a widget:
Register it in
class QuoteWidgetReceiver : GlanceAppWidgetReceiver() { override val glanceAppWidget = QuoteWidget() }AndroidManifest.xmlwith theandroid.appwidget.action.APPWIDGET_UPDATEintent filter and anandroid.appwidget.providermeta-data pointing at yourres/xml/<widget>_info.xml. - Build the bridge with that receiver class so
publishcan broadcast the update:val bridge = androidWidgetBridge(context, WidgetBridgeConfig(schemaVersion = 1), QuoteFeed.serializer(), QuoteWidgetReceiver::class.java) - Read in
provideGlance:override suspend fun provideGlance(context: Context, id: GlanceId) { val feed = bridge.read() val bitmap = feed?.assetPath("q1.jpg")?.let(BitmapFactory::decodeFile) provideContent { /* your Glance UI */ } }
Read inside the composition. Glance keeps a session alive for tens of seconds after a render, and update() on a live session only recomposes; code before provideContent does not run again. Bump an in-process counter from the receiver and key the read on it:
class QuoteWidgetReceiver : GlanceAppWidgetReceiver() {
override val glanceAppWidget = QuoteWidget()
override fun onReceive(context: Context, intent: Intent) {
if (intent.action == AppWidgetManager.ACTION_APPWIDGET_UPDATE) QuoteWidget.refreshes.value++
super.onReceive(context, intent)
}
}
// in provideGlance:
provideContent {
val refresh by QuoteWidget.refreshes.collectAsState()
val model = remember(refresh) { loadModel(bridge) }
QuoteCard(model)
}
Storage is <filesDir>/widgetbridge (change the folder with WidgetBridgeConfig.directoryName). publish and read do file I/O; call them from a background dispatcher.