SizeMode
sealed interface SizeMode
Modes describing how the GlanceAppWidget
should handle size specification.
Note: Size modes that support multiple sizes (Exact
, Responsive
) run the composable passed to
to provideContent
concurrently for each size. This has a number of important implications.
Since an instance of the content is running for each size, all of the State objects in the
content will have an instance for each size.
For example, in Exact mode, let's say the AppWidgetHost asks for 2 sizes, portrait and landscape.
In the code below, there will end up being two instances of the count
variable, one for each
size:
provideContent { var count by remember { mutableStateOf(0) } Button( text = "Increment count: $count", onClick = { count++ } )
}
If the button is clicked while the widget is displayed in portrait size, the count
variable is
updated for both sizes. This is so that, if the device orientation changes and the host displays
the landscape layout, it will be consistent with the state in portrait. This works because
lambdas that are at the same place in the composition will be mapped to the same default key in
all sizes. So triggering one will trigger the corresponding lambdas in other sizes.
This means that lambdas will be called multiple times when they are triggered, which can have unexpected effects if state is not handled correctly. In order to prevent some external action from being triggered multiple times at once, you should conflate requests so that only one is active at a time, e.g. using MutableStateFlow.
To prevent this behavior, you can use the androidx.compose.runtime.key
composable to set
different default lambda keys for each size, so that they do not trigger each other:
provideContent { key(LocalSize.current) { var count by remember { mutableStateOf(0) } Button( text = "Increment count: $count", onClick = { count++ } ) }
}
To disable this behavior on a per-lambda basis, use androidx.glance.action.action
to set a
custom lambda key based on the current size:
provideContent { var count by remember { mutableStateOf(0) } Button( text = "Increment count: $count", onClick = action("incrementCount-${LocalSize.current}") { count++ } )
}
In both of the last two examples, when the button is clicked, only the lambda for the currently visible size will be triggered.
Note that the above does not work for effects, which will always be triggered for each size. Use effects to update state variables in the composition, otherwise be sure to handle any duplicate triggering that may occur.