https://kotlinlang.org logo
z

Zaki Shaikh

01/10/2023, 2:11 PM
Hi everyone, I am working on an app using Jetpack Compose GoogleMap in which i am drawing polygon by user input it is working fine but has a performance issue it is leading to a UI Junk and can't render plolygon seamlessly by user touch input. Code in thread.
Copy code
@Composable
fun MapViewFragmentScreen(
    viewModel: SignUpAndEditProfileViewModel,
    viewLand: Land?,
    onDone: () -> Unit
) {
    val context = LocalContext.current
    val spacing = LocalSpacing.current
    val shape = LocalCustomShapes.current.mediumShape
    val cameraPositionState = rememberCameraPositionState {
        if (viewModel.coordinates.value.isNotEmpty()) {
            viewModel.coordinates.value.getCenterCoordinate()?.let {
                position = CameraPosition.fromLatLngZoom(it, MAP_ZOOM_FACTOR)
            }
        } else {
            DataHolder.getInstance().lastKnownLocation?.let {
                position = CameraPosition.fromLatLngZoom(
                    LatLng(it.latitude, it.longitude),
                    MAP_ZOOM_FACTOR
                )
            }
        }
    }
    val uiSettings by remember {
        mutableStateOf(
            MapUiSettings(
                myLocationButtonEnabled = true,
            )
        )
    }
    val properties by remember {
        mutableStateOf(MapProperties(mapType = MapType.NORMAL, isMyLocationEnabled = true))
    }
    var isAddingBoundary by remember { mutableStateOf(false) }
    Box(modifier = Modifier.fillMaxSize()) {
        GoogleMap(
            modifier = Modifier.fillMaxSize(),
            cameraPositionState = cameraPositionState,
            properties = properties,
            uiSettings = uiSettings,
            onMapLoaded = {
                moveMapToLocation(viewLand, cameraPositionState, viewModel)
            },
            onMapClick = {
                if (isAddingBoundary) {
                    viewModel.coordinates.postValue(viewModel.coordinates.value + it)
                }
            }
        ) {
            DrawLand(
                getCoordinates = { viewModel.coordinates.value },
                center = viewModel.coordinates.value.getCenterCoordinate(),
                getFarmName = { viewModel.farmName.value }
            )

            /*viewModel.lands.forEach { land ->
                land.coordinates?.map { LatLng(it.latitude, it.longitude) }?.let {
                    DrawLand(
                        getCoordinates = { it },
                        center = it.getCenterCoordinate(),
                        getFarmName = { land.landName ?: "N/A" }
                    )
                }
            }*/
        }

        Column(
            modifier = Modifier
                .wrapContentWidth()
                .align(Alignment.BottomStart)
                .padding(spacing.medium)
                .border(width = .3.dp, color = Color.White, shape = shape)
                .background(color = Color.OrangePeel.copy(alpha = .1f), shape = shape)
                .padding(spacing.small),
            verticalArrangement = Arrangement.spacedBy(spacing.extraSmall)
        ) {
            MapButton(
                iconId = if (isAddingBoundary) R.drawable.ic_close else R.drawable.ic_add_boundary
            ) {
                if (!isAddingBoundary) {
                    viewModel.coordinates.clear()
                    viewModel.farmLocation = null
                    context.showToast(R.string.select_your_land)
                }

                isAddingBoundary = !isAddingBoundary
            }

            if (viewModel.coordinates.value.isNotEmpty() && isAddingBoundary) {
                MapButton(
                    iconId = R.drawable.ic_clear_point
                ) {
                    viewModel.coordinates.postValue(
                        viewModel.coordinates.value - viewModel.coordinates.value.last()
                    )
                }
            }

            MapButton(
                iconId = R.drawable.ic_done,
                onClick = {
                    if (viewModel.coordinates.value.size > 2) {
                        viewModel.farmLocation =
                            viewModel.coordinates.value.getCenterCoordinate()
                                ?.getLocationName(context)
                        onDone()
                    } else {
                        context.showToast(R.string.farm_least_points_msg)
                    }
                }
            )

        }
    }
}
Copy code
@Composable
fun DrawLand(
    getCoordinates: () -> List<LatLng>,
    center: LatLng?,
    getFarmName: () -> String
) {
    val context = LocalContext.current
    val marker = bitmapDescriptor(context, R.mipmap.ic_sign_up_location_field_foreground)
    val circle = bitmapDescriptor(context, R.drawable.ic_circle, 20)
    getCoordinates().let { coordinates ->
        if (coordinates.isNotEmpty()) {
            Polygon(
                points = getCoordinates(),
                fillColor = Color.Green.copy(alpha = .2f),
                strokeColor = Color.Cameron,
                strokeJointType = JointType.BEVEL,
                strokeWidth = 5f
            )

            center?.let {
                Marker(
                    position = it,
                    title = getFarmName(),
                    snippet = it.getLocationName(context),
                    icon = marker
                )
            }

            getCoordinates().forEach { position ->
                Marker(
                    position = position,
                    title = getFarmName(),
                    snippet = position.getLocationName(context),
                    icon = circle
                )
            }
        }
    }
}
m

myanmarking

01/10/2023, 3:36 PM
from my experience, legacy map properties are never Immutable. And using List<T> is also a performance bottleneck
z

Zaki Shaikh

01/10/2023, 3:50 PM
So is there any alternative to List<T>
m

myanmarking

01/10/2023, 3:51 PM
this would do:
Copy code
@Stable
@Keep
data class ImmutableList<out T>(val list: List<T>) : List<T> by list
use always this when using lists to compose
should solve part of the problem
z

Zaki Shaikh

01/10/2023, 3:52 PM
Ok thanks I try it
m

myanmarking

01/10/2023, 3:52 PM
you need to use ‘ImmutableList’ as type in composable params. You cannot use ImmutableList but pass in List as type. Compose only looks for the declared type
z

Zaki Shaikh

01/10/2023, 3:53 PM
Ok
m

myanmarking

01/10/2023, 3:56 PM
are you sing a factory for bitmapDescriptor ?
c

Colton Idle

01/12/2023, 12:38 AM
Also, are you trying in release mode with r8 enabled?
z

Zaki Shaikh

01/12/2023, 5:55 AM
@myanmarking yes I am using
32 Views