Fabio Berta
04/11/2023, 2:22 PMAndroidView . I'm using it to wrap a maplibre (mapbox v9 fork) map in a composable Map. If I store the current camera position of the map as a mutableStateOf in Map , add a position listener that updates the state in the factory and set the position in the update block of the AndroidView, all is fine: the position updates when the state changes and the AndroidView itself does not recompose. But if that state is hoisted outside of Map and passed in as a param, AndroidView itself recomposes and the performance is bad. I checked that the factory is only called once though and update is called correctly. I'm trying to figure out 2 things, why does AndroidView itself recompose in this case and not just call update and why is the performance bad, it seems like factory is not called again but only updated which seems like what is supposed to happen.Jakub Syty
04/11/2023, 2:58 PMJakub Syty
04/11/2023, 2:58 PMephemient
04/11/2023, 3:03 PMFabio Berta
04/11/2023, 3:04 PMonReset but thought this was more appropriate for lazy layoutsZach Klippenstein (he/him) [MOD]
04/11/2023, 8:56 PMFabio Berta
04/11/2023, 9:43 PMFabio Berta
04/11/2023, 9:43 PM@Composable
fun HoistedStateMap(
position: MapPosition,
onPositionChange: (MapPosition) -> Unit,
modifier: Modifier = Modifier,
) {
AndroidView(
factory = { context ->
MapView(context).also { mapView ->
mapView.getMapAsync { map ->
map.apply {
addOnCameraMoveListener { onPositionChange(cameraPosition.toMapPosition()) }
setStyle(STYLE_URL)
}
}
}
},
update = { mapView ->
mapView.getMapAsync { map ->
position.toCameraPosition().let {
if (it != map.cameraPosition) {
map.cameraPosition = it
}
}
}
},
modifier = modifier,
)
}Fabio Berta
04/11/2023, 9:43 PMFabio Berta
04/11/2023, 9:43 PM@Composable
fun InternalStateMap(
modifier: Modifier = Modifier,
) {
var position by remember { mutableStateOf(initialPosition) }
AndroidView(
factory = { context ->
MapView(context).also { mapView ->
mapView.getMapAsync { map ->
map.apply {
addOnCameraMoveListener { position = cameraPosition.toMapPosition() }
setStyle(STYLE_URL)
}
}
}
},
update = { mapView ->
mapView.getMapAsync { map ->
position.toCameraPosition().let {
if (it != map.cameraPosition) {
map.cameraPosition = it
}
}
}
},
modifier = modifier,
)
}Fabio Berta
04/11/2023, 9:44 PMFabio Berta
04/11/2023, 9:47 PMFabio Berta
04/11/2023, 9:47 PMdata class MapPosition(val coordinates: Coordinates, val zoom: Double)ephemient
04/11/2023, 9:47 PMMapPosition @Stable or @Immutable or neither?Fabio Berta
04/11/2023, 9:48 PMdata class Coordinates(val lat: Latitude, val lon: Longitude)
@JvmInline
value class Latitude(val value: Double)
@JvmInline
value class Longitude(val value: Double)Fabio Berta
04/11/2023, 9:48 PMFabio Berta
04/11/2023, 9:50 PMMapPosition with Stable doesn't change anythingFabio Berta
04/11/2023, 9:55 PMFabio Berta
04/14/2023, 3:26 PMMapPosition was indeed not stable because it came from a module without compose. I adjusted that and now it is stable and the composable is skippable. However, nothing changed in terms of performance. Obviously, HoistedStateMap can't be skipped because position actually changes. In that sense, it also makes sense that this change didn't have any effect.Fabio Berta
04/14/2023, 3:26 PMFabio Berta
04/14/2023, 3:26 PM@Composable
fun HoistedStateMap(
position: MapPosition,
onPositionChange: (MapPosition) -> Unit,
modifier: Modifier = Modifier,
) {
val mapPosition = rememberUpdatedState(position)
AndroidView(
factory = { context ->
MapView(context).also { mapView ->
mapView.getMapAsync { map ->
map.apply {
addOnCameraMoveListener { onPositionChange(cameraPosition.toMapPosition()) }
setStyle(STYLE_URL)
}
}
}
},
update = { mapView ->
mapView.getMapAsync { map ->
mapPosition.value.toCameraPosition().let {
if (it != map.cameraPosition) {
map.cameraPosition = it
}
}
}
},
modifier = modifier,
)
}Fabio Berta
04/14/2023, 3:26 PMmapPosition from rememberUpdatedState(position) is an object that itself doesn't changeFabio Berta
04/14/2023, 3:27 PMupdate function of AndroidView is supposed to be used if this is required?Fabio Berta
04/14/2023, 3:27 PMZach Klippenstein (he/him) [MOD]
04/14/2023, 4:23 PMFabio Berta
04/14/2023, 4:23 PMFabio Berta
04/14/2023, 4:24 PMZach Klippenstein (he/him) [MOD]
04/14/2023, 4:28 PMFabio Berta
04/14/2023, 4:30 PM