:loudspeaker::loudspeaker::loudspeaker: We want yo...
# glance
m
📢📢📢 We want your feedback 📢📢📢 We have great news… 🥁🥁 Glance for appwidgets can now support Recomposition! Tl;dr: it’s a big change and we want your feedback. Please try the latest androidx snapshot and let us know what you think! (report bugs here or in this channel). What does this mean? •
GlanceAppWidget
now starts a session (using
WorkManager
) to compose Glance and respond to state changes / interactions by recomposing • This enables standard Compose patterns like
remember/mutableStateOf
, side effects, etc. •
GlanceAppWidget
supports defining actions as lambdas (like normal Compose) •
provideGlance()
is a new entry point to load data before the composition
Copy code
// Required to enable recomposition
override val sessionManager = GlanceSessionManager

@Composable
override suspend fun AppWidgetProviderScope.provideGlance(
    context: Context,
    glanceId: GlanceId,
) {
    setContent {
        var count by remember { mutableStateOf(0) }
        Button(
            text = "Count $count",
            modifier = GlanceModifier.fillMaxSize(),
            onClick = {
                count++ 
            }
        )
    }
}
➡️ Check the ImageAppWidget.kt demo
👌 5
🦜 7
jetpack compose 11
K 13
t
While I love the result, adding appstartup + workmanager + room on an app is big. Have you measured the app size changes triggered by this for apps without those and who do not want to use those?
m
its still a WIP, but we will review it. Although spliting this into a different module would make things even more complex. Plus, most of app use WM
t
5M downloads and none of my app do. There's still quite a few issues https://issuetracker.google.com/issues/254846063 + many others tied to database issues crashing the app without proper / easy possible recovery. In my case if it's the default behavior and we can't exclude the deps and not use this it's a reason to return to traditional widgets.
m
Sometimes we need to do trade offs and as I said WM is used by most of the apps, in addition to be the recommended way. if it’s really important for your use case to have the smallest size possible then it might be better to use RemoteViews directly or consider Dynamic Features
t
Size and stability 🙂 Main app is 100% crashrate/anr free because of some of the choice to not use things that have issues. I'd love to have know earlier you'd go that huge deps road 😞 Just added a bunch of Glance widgets to the new app.
m
We will look into it, for example for material it did make sense, but this is going to be core part of the library
t
Well I don't really understand the purpose of being dependent of WM in that case seeing how the lifecycle of widget works, but that's your call.
m
This change comes from long design reviews to find a way to support recomposition for widgets. It’s not a trivial thing and due to the lifecycle of widgets we need a way to execute those changes while preserving system health. WM is the right tool for that
t
Well take your example: https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:glance/g[…]n/java/androidx/glance/appwidget/demos/ImageAppWidget.kt;l=53 the remember here have unclear result in the compose world. remember is bound to the composable being there and not supposed to be saved on app restart, else it would be rememberSaveable how would that work in the scope of Glance, what is the lifetime of that remember scope what is that value on a reboot? In the same idea if you observe state changes make by the application outside of the widget, how does that work? App is kept alive or else it won't do what people would expect.
m
I can get into details now, but this is implemented with the concept of Sessions, while the session is there the composition is alive, if the session is closed (e.g process is killed) there won’t be recomposition and all state will be destroyed
for persisting data you should keep using the GlanceStateDefinition or your own app mechanism
t
So that's normal Widget lifecycle behavior and I do not understand the need for WM. Since it's app lifecycle bound you can handle the sessions via the app (and eventually androidx startup to automate the creation with manual way for advanced people). And any interaction with widgets still works via intent that restart the app. What's the added value of WM here ?
m
Recomposition/side-effects/etc happens in the background and requires a background thread. Dealing with this without WM would be much harder and errorprone. I can get into details of weeks of design review but feel free to open a FR in our tracker
t
I can't make an FR to say don't do X if I do not understand how you reached the X decision else it's an indie dev complaining without arguments against a team decision. I still don't see what WM adds to manage a background thread. Unless you want to start using foreground services and expedited things but then faces all the OS limits in many cases that would not work. Anyway I'll look the code and try to understand the reasoning.
Checking the PR https://github.com/androidx/androidx/commit/8d06cca3c03bd5b51a6e2a211d11e2d1f09865c1 and WM is used to maintain a keyed list of coroutine Jobs in Default dispatcher. Makes even less sense. I'll open a FR hoping someone will explain if there's hidden future goals requiring WM.
BTW unrelated but I've also opened https://issuetracker.google.com/issues/257513022 and I have no idea how to repro.
And in case it needs triage https://issuetracker.google.com/issues/258012261 is the issue for this.
a
This is big, like realllllllyyyy big. Big ups to y'all @Marcel Pinto!!!!!
a
plus1 Have been waiting for this feature! Thanks 🙌
r
Hi @Marcel Pinto I’ve tested it with a periodic update state on every N seconds. I tried to implememt Chronomoter but it stopped recomposing some times ago when the sceen is off
t
This is completely to be expected, the way Glance handle this does not have any impact on the application lifecycle, so the application will get killed when the os decide to and it will stop, you need a foreground service to try to prevent that, but will have to fight OEMs https://dontkillmyapp.com/
r
But old xml style Chronometer is working well @Tolriq
m
The chronometer is part of the platform available remote views. The host is basically hosting a chronometer view, but the widget owner is not active. As @Tolriq said once the app is killed any continues update will be stopped. Widgets are not intended to be all the time active.
If you need the chronometer you can use AndroidRemoteView compostable to host it