Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using Marker or MarkerComposable in Clustering #641

Open
feivur opened this issue Oct 29, 2024 · 9 comments
Open

Using Marker or MarkerComposable in Clustering #641

feivur opened this issue Oct 29, 2024 · 9 comments
Labels
triage me I really want to be triaged. type: feature request ‘Nice-to-have’ improvement, new feature or different behavior or design.

Comments

@feivur
Copy link

feivur commented Oct 29, 2024

Is your feature request related to a problem? Please describe.
Now we cannot use Marker or MarkerComposable in blocks clusterContent and clusterItemContent of Clustering (com.google.maps.android.compose.clustering.Clustering)
Therefore, it is not possible to drag and drop custom markers.

Describe the solution you'd like
I want to use features together: custom markers, dragging and clustering.

MarkerComposableinside Clustering leads to a crash: case 1
java.lang.IllegalStateException: The ComposeView was measured to have a width or height of zero. Make sure that the content has a non-zero size.

Marker inside Clustering leads to a crash: case 2
java.lang.IllegalStateException: Invalid applier

maps-compose version is 6.1.2

Case 1

@Composable
private fun CustomUiClustering(items: List<MyItem>) {
    Clustering(
        items = items,
        clusterItemContent = {
            MarkerComposable(
                state = rememberMarkerState(position = it.itemPosition)
            ) {
                Text(
                    modifier = Modifier.size(40.dp),
                    text = "test",
                )
            }
        }
    )
}
FATAL EXCEPTION: main
                     Process: com.google.maps.android.compose, PID: 28881
                     java.lang.IllegalStateException: The ComposeView was measured to have a width or height of zero. Make sure that the content has a non-zero size.
                     	at com.google.maps.android.compose.RememberComposeBitmapDescriptorKt.renderComposableToBitmapDescriptor(RememberComposeBitmapDescriptor.kt:58)
                     	at com.google.maps.android.compose.RememberComposeBitmapDescriptorKt.access$renderComposableToBitmapDescriptor(RememberComposeBitmapDescriptor.kt:1)
                     	at com.google.maps.android.compose.RememberComposeBitmapDescriptorKt.rememberComposeBitmapDescriptor(RememberComposeBitmapDescriptor.kt:29)
                     	at com.google.maps.android.compose.MarkerKt.MarkerComposable-Khg_OnI(Marker.kt:313)
                     	at com.google.maps.android.compose.markerexamples.ComposableSingletons$MarkerClusteringActivityKt$lambda-3$1.invoke(MarkerClusteringActivity.kt:172)
                     	at com.google.maps.android.compose.markerexamples.ComposableSingletons$MarkerClusteringActivityKt$lambda-3$1.invoke(MarkerClusteringActivity.kt:171)
                     	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:118)
                     	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:35)
                     	at com.google.maps.android.compose.clustering.ComposeUiClusterRenderer$createAndAddView$view$2.invoke(ClusterRenderer.kt:95)
                     	at com.google.maps.android.compose.clustering.ComposeUiClusterRenderer$createAndAddView$view$2.invoke(ClusterRenderer.kt:95)
                     	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:109)
                     	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:35)
                     	at com.google.maps.android.compose.clustering.ComposeUiClusterRenderer$InvalidatingComposeView.Content(ClusterRenderer.kt:220)
                     	at androidx.compose.ui.platform.AbstractComposeView$ensureCompositionCreated$1.invoke(ComposeView.android.kt:259)
                     	at androidx.compose.ui.platform.AbstractComposeView$ensureCompositionCreated$1.invoke(ComposeView.android.kt:258)
                     	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:109)
                     	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:35)
                     	at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:380)
                     	at androidx.compose.ui.platform.CompositionLocalsKt.ProvideCommonCompositionLocals(CompositionLocals.kt:216)
                     	at androidx.compose.ui.platform.AndroidCompositionLocals_androidKt$ProvideAndroidCompositionLocals$3.invoke(AndroidCompositionLocals.android.kt:132)
                     	at androidx.compose.ui.platform.AndroidCompositionLocals_androidKt$ProvideAndroidCompositionLocals$3.invoke(AndroidCompositionLocals.android.kt:131)
                     	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:109)
                     	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:35)
                     	at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:380)
                     	at androidx.compose.ui.platform.AndroidCompositionLocals_androidKt.ProvideAndroidCompositionLocals(AndroidCompositionLocals.android.kt:121)
                     	at androidx.compose.ui.platform.WrappedComposition$setContent$1$1$3.invoke(Wrapper.android.kt:155)
                     	at androidx.compose.ui.platform.WrappedComposition$setContent$1$1$3.invoke(Wrapper.android.kt:154)
                     	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:109)
                     	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:35)
                     	at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:401)
                     	at androidx.compose.ui.platform.WrappedComposition$setContent$1$1.invoke(Wrapper.android.kt:154)
                     	at androidx.compose.ui.platform.WrappedComposition$setContent$1$1.invoke(Wrapper.android.kt:133)
                     	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:109)
                     	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:35)
                     	at androidx.compose.runtime.ActualJvm_jvmKt.invokeComposable(ActualJvm.jvm.kt:97)
                     	at androidx.compose.runtime.ComposerImpl.doCompose(Composer.kt:3595)
                     	at androidx.compose.runtime.ComposerImpl.composeContent$runtime_release(Composer.kt:3522)
                     	at androidx.compose.runtime.CompositionImpl.composeContent(Composition.kt:743)
                     	at androidx.compose.runtime.Recomposer.composeInitial$runtime_release(Recomposer.kt:1122)
                     	at androidx.compose.runtime.ComposerImpl$CompositionContextImpl.composeInitial$runtime_release(Composer.kt:3876)
                     	at androidx.compose.runtime.CompositionImpl.composeInitial(Composition.kt:649)
                     	at androidx.compose.runtime.CompositionImpl.setContent(Composition.kt:635)
                     	at androidx.compose.ui.platform.WrappedComposition$setContent$1.invoke(Wrapper.android.kt:133)
                     	at androidx.compose.ui.platform.WrappedComposition$setContent$1.invoke(Wrapper.android.kt:124)
                     	at androidx.compose.ui.platform.AndroidComposeView.setOnViewTreeOwnersAvailable(AndroidComposeView.android.kt:1631)
                     	at androidx.compose.ui.platform.WrappedComposition.setContent(Wrapper.android.kt:124)
                     	at androidx.compose.ui.platform.WrappedComposition.onStateChanged(Wrapper.android.kt:180)
                     	at androidx.lifecycle.LifecycleRegistry$ObserverWithState.dispatchEvent(LifecycleRegistry.jvm.kt:320)
                     	at androidx.lifecycle.LifecycleRegistry.addObserver(LifecycleRegistry.jvm.kt:198)
                     	at androidx.compose.ui.platform.WrappedComposition$setContent$1.invoke(Wrapper.android.kt:131)
                     	at androidx.compose.ui.platform.WrappedComposition$setContent$1.invoke(Wrapper.android.kt:124)
                     	at androidx.compose.ui.platform.AndroidComposeView.onAttachedToWindow(AndroidComposeView.android.kt:1712)
                     	at android.view.View.dispatchAttachedToWindow(View.java:23244)
                     	at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3722)
                     	at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3729)
                     	at android.view.ViewGroup.addViewInner(ViewGroup.java:5604)
                     	at android.view.ViewGroup.addView(ViewGroup.java:5352)
                     	at android.view.ViewGroup.addView(ViewGroup.java:5292)
                     	at android.view.ViewGroup.addView(ViewGroup.java:5264)
                     	at com.google.maps.android.compose.MapComposeViewRenderKt.startRenderingComposeView(MapComposeViewRender.kt:46)
                     	at com.google.maps.android.compose.MapComposeViewRenderKt$rememberComposeUiViewRenderer$1$1.startRenderingView(MapComposeViewRender.kt:92)
                     	at com.google.maps.android.compose.clustering.ComposeUiClusterRenderer.createAndAddView(ClusterRenderer.kt:99)
                     	at com.google.maps.android.compose.clustering.ComposeUiClusterRenderer.onClustersChanged(ClusterRenderer.kt:67)
                     	at com.google.maps.android.clustering.ClusterManager$ClusterTask.onPostExecute(ClusterManager.java:322)
                     	at com.google.maps.android.clustering.ClusterManager$ClusterTask.onPostExecute(ClusterManager.java:308)
                     	at android.os.AsyncTask.finish(AsyncTask.java:771)
                     	at android.os.AsyncTask.-$$Nest$mfinish(Unknown Source:0)
                     	at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:788)
                     	at android.os.Handler.dispatchMessage(Handler.java:106)
                     	at android.os.Looper.loopOnce(Looper.java:230)
                     	at android.os.Looper.loop(Looper.java:319)
                     	at android.app.ActivityThread.main(ActivityThread.java:9063)
                     	at java.lang.reflect.Method.invoke(Native Method)
                     	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:588)
                     	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1103)

Case 2

@Composable
private fun CustomUiClustering(items: List<MyItem>) {
    Clustering(
        items = items,
        clusterItemContent = {
            Marker(
                state = rememberMarkerState(position = it.itemPosition)
            )
        }
    )
}
FATAL EXCEPTION: main
                     Process: com.google.maps.android.compose, PID: 32440
                     java.lang.IllegalStateException: Invalid applier
                     	at androidx.compose.runtime.ComposablesKt.invalidApplier(Composables.kt:476)
                     	at com.google.maps.android.compose.MarkerKt.MarkerImpl-khPtz74(Marker.kt:944)
                     	at com.google.maps.android.compose.MarkerKt.Marker-qld6geY(Marker.kt:238)
                     	at com.google.maps.android.compose.markerexamples.ComposableSingletons$MarkerClusteringActivityKt$lambda-2$1.invoke(MarkerClusteringActivity.kt:166)
                     	at com.google.maps.android.compose.markerexamples.ComposableSingletons$MarkerClusteringActivityKt$lambda-2$1.invoke(MarkerClusteringActivity.kt:165)
                     	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:118)
                     	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:35)
                     	at com.google.maps.android.compose.clustering.ComposeUiClusterRenderer$createAndAddView$view$2.invoke(ClusterRenderer.kt:95)
                     	at com.google.maps.android.compose.clustering.ComposeUiClusterRenderer$createAndAddView$view$2.invoke(ClusterRenderer.kt:95)
                     	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:109)
                     	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:35)
                     	at com.google.maps.android.compose.clustering.ComposeUiClusterRenderer$InvalidatingComposeView.Content(ClusterRenderer.kt:220)
                     	at androidx.compose.ui.platform.AbstractComposeView$ensureCompositionCreated$1.invoke(ComposeView.android.kt:259)
                     	at androidx.compose.ui.platform.AbstractComposeView$ensureCompositionCreated$1.invoke(ComposeView.android.kt:258)
                     	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:109)
                     	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:35)
                     	at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:380)
                     	at androidx.compose.ui.platform.CompositionLocalsKt.ProvideCommonCompositionLocals(CompositionLocals.kt:216)
                     	at androidx.compose.ui.platform.AndroidCompositionLocals_androidKt$ProvideAndroidCompositionLocals$3.invoke(AndroidCompositionLocals.android.kt:132)
                     	at androidx.compose.ui.platform.AndroidCompositionLocals_androidKt$ProvideAndroidCompositionLocals$3.invoke(AndroidCompositionLocals.android.kt:131)
                     	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:109)
                     	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:35)
                     	at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:380)
                     	at androidx.compose.ui.platform.AndroidCompositionLocals_androidKt.ProvideAndroidCompositionLocals(AndroidCompositionLocals.android.kt:121)
                     	at androidx.compose.ui.platform.WrappedComposition$setContent$1$1$3.invoke(Wrapper.android.kt:155)
                     	at androidx.compose.ui.platform.WrappedComposition$setContent$1$1$3.invoke(Wrapper.android.kt:154)
                     	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:109)
                     	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:35)
                     	at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:401)
                     	at androidx.compose.ui.platform.WrappedComposition$setContent$1$1.invoke(Wrapper.android.kt:154)
                     	at androidx.compose.ui.platform.WrappedComposition$setContent$1$1.invoke(Wrapper.android.kt:133)
                     	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:109)
                     	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:35)
                     	at androidx.compose.runtime.ActualJvm_jvmKt.invokeComposable(ActualJvm.jvm.kt:97)
                     	at androidx.compose.runtime.ComposerImpl.doCompose(Composer.kt:3595)
                     	at androidx.compose.runtime.ComposerImpl.composeContent$runtime_release(Composer.kt:3522)
                     	at androidx.compose.runtime.CompositionImpl.composeContent(Composition.kt:743)
                     	at androidx.compose.runtime.Recomposer.composeInitial$runtime_release(Recomposer.kt:1122)
                     	at androidx.compose.runtime.ComposerImpl$CompositionContextImpl.composeInitial$runtime_release(Composer.kt:3876)
                     	at androidx.compose.runtime.CompositionImpl.composeInitial(Composition.kt:649)
                     	at androidx.compose.runtime.CompositionImpl.setContent(Composition.kt:635)
                     	at androidx.compose.ui.platform.WrappedComposition$setContent$1.invoke(Wrapper.android.kt:133)
                     	at androidx.compose.ui.platform.WrappedComposition$setContent$1.invoke(Wrapper.android.kt:124)
                     	at androidx.compose.ui.platform.AndroidComposeView.setOnViewTreeOwnersAvailable(AndroidComposeView.android.kt:1631)
                     	at androidx.compose.ui.platform.WrappedComposition.setContent(Wrapper.android.kt:124)
                     	at androidx.compose.ui.platform.WrappedComposition.onStateChanged(Wrapper.android.kt:180)
                     	at androidx.lifecycle.LifecycleRegistry$ObserverWithState.dispatchEvent(LifecycleRegistry.jvm.kt:320)
                     	at androidx.lifecycle.LifecycleRegistry.addObserver(LifecycleRegistry.jvm.kt:198)
                     	at androidx.compose.ui.platform.WrappedComposition$setContent$1.invoke(Wrapper.android.kt:131)
                     	at androidx.compose.ui.platform.WrappedComposition$setContent$1.invoke(Wrapper.android.kt:124)
                     	at androidx.compose.ui.platform.AndroidComposeView.onAttachedToWindow(AndroidComposeView.android.kt:1712)
                     	at android.view.View.dispatchAttachedToWindow(View.java:23244)
                     	at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3722)
                     	at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3729)
                     	at android.view.ViewGroup.addViewInner(ViewGroup.java:5604)
                     	at android.view.ViewGroup.addView(ViewGroup.java:5352)
                     	at android.view.ViewGroup.addView(ViewGroup.java:5292)
                     	at android.view.ViewGroup.addView(ViewGroup.java:5264)
                     	at com.google.maps.android.compose.MapComposeViewRenderKt.startRenderingComposeView(MapComposeViewRender.kt:46)
                     	at com.google.maps.android.compose.MapComposeViewRenderKt$rememberComposeUiViewRenderer$1$1.startRenderingView(MapComposeViewRender.kt:92)
                     	at com.google.maps.android.compose.clustering.ComposeUiClusterRenderer.createAndAddView(ClusterRenderer.kt:99)
                     	at com.google.maps.android.compose.clustering.ComposeUiClusterRenderer.onClustersChanged(ClusterRenderer.kt:67)
                     	at com.google.maps.android.clustering.ClusterManager$ClusterTask.onPostExecute(ClusterManager.java:322)
                     	at com.google.maps.android.clustering.ClusterManager$ClusterTask.onPostExecute(ClusterManager.java:308)
                     	at android.os.AsyncTask.finish(AsyncTask.java:771)
                     	at android.os.AsyncTask.-$$Nest$mfinish(Unknown Source:0)
                     	at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:788)
                     	at android.os.Handler.dispatchMessage(Handler.java:106)
                     	at android.os.Looper.loopOnce(Looper.java:230)
                     	at android.os.Looper.loop(Looper.java:319)
                     	at android.app.ActivityThread.main(ActivityThread.java:9063)
                     	at java.lang.reflect.Method.invoke(Native Method)
                     	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:588)
                     	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1103)
@feivur feivur added triage me I really want to be triaged. type: feature request ‘Nice-to-have’ improvement, new feature or different behavior or design. labels Oct 29, 2024
@ln-12
Copy link
Contributor

ln-12 commented Nov 22, 2024

We are also experiencing case 1. This issue seems to be a follow up to this issue/PR/comment.

I our case it also happens without clustering (also on v6.1.2):

GoogleMap(
    cameraPositionState = cameraPositionState,
    uiSettings = MapUiSettings(
        compassEnabled = false,
        indoorLevelPickerEnabled = false,
        mapToolbarEnabled = false,
        myLocationButtonEnabled = false,
        rotationGesturesEnabled = false,
        scrollGesturesEnabled = false,
        scrollGesturesEnabledDuringRotateOrZoom = false,
        tiltGesturesEnabled = false,
        zoomControlsEnabled = false,
        zoomGesturesEnabled = false,
    ),
    liteMode = true,
    modifier = Modifier
        .height(115.dp)
        .fillMaxWidth(),
) {
    val markerState = remember(coordinates) { MarkerState(position = coordinates) }
    MarkerComposable(
        state = markerState,
        title = stringResource(R.string.some_description),
    ) {
        Icon(
            imageVector = MyDrawables.MapMarker,
            contentDescription = null,
            tint = Color.Blue,
            modifier = Modifier.size(16.dp),
        )
    }
}

I am already defining a size for the icon, so my only idea would be to use requiredSize instead to ignore any incoming constraints. Do you think that would help? Unfortunately this issue is relatively rare and we could not reproduce it yet locally, only ours users are able to get it.

@ln-12
Copy link
Contributor

ln-12 commented Dec 19, 2024

I have additional information. The requireSize modifier did not help with that crash. However, I copied the rememberComposeBitmapDescriptor implementation and added a workaround that helps + some logging here:

    if (composeView.measuredWidth == 0 || composeView.measuredHeight == 0) {
        val ex = IllegalStateException(
            "The ComposeView was measured to have a width or height of " +
                "zero. Make sure that the content has a non-zero size.",
        )

        Logger.ex(
            ex = ex,
            message = "Parent: size=${parent.size}, width=${parent.width}, height=${parent.height}\n" +
                "Compose view: size=${composeView.size}, width=${composeView.width}, height=${composeView.height}\n" +
                "Measured: width=${composeView.measuredWidth}, height=${composeView.measuredHeight}",
        )

        return null
    }

The result is the following:

Parent: size=2, width=1080, height=1862
Compose view: size=1, width=0, height=0
Measured: width=0, height=0

So apparently the actual issue not the parent having a zero width/height but rather the compose view not being measured correctly. Also, I can see that according to the Sentry log, the fragment in which the ComposeView with the GoogleMap composable is used was already destroyed and detached when this crash happened. So it seems to be an issue (race condition?) when navigating away from the screen.

@mariohide
Copy link

In my case, it's not related to clustering. I have fragments in a ViewPager, and a Compose map in one of the fragments. When the fragment becomes invisible and the marker data source changes, a crash occurs.

To work around this issue, I added a boolean flag:

if (uiState.isContainerVisible) {
    uiState.markers.forEach { marker ->
        MarkerComposable(...) {
            CustomMarker(marker)
        }
    }
}

isContainerVisible is set to true 200ms after the fragment resumes and to false when the fragment pauses.

@bubenheimer
Copy link
Contributor

@mariohide are you able to provide a complete and somewhat minimal repro? I am not a maintainer, but I think a good repro may help with seeing this fixed, as it seems to happen in specific circumstances.

Right now this issue does not seem to have a stacktrace for the non-clustering case. The non-clustering codebase is somewhat different from (simpler than) the clustering kind.

@mariohide
Copy link

mariohide commented Jan 1, 2025 via email

@mariohide
Copy link

mariohide commented Jan 3, 2025

@bubenheimer Hi, I've created a repo that reproduce this:

  1. Build and install;
  2. Navigate to "fragment2";
  3. click "Add marker cause crash" button.

You got a crash.

@bubenheimer
Copy link
Contributor

Thanks for the repro, that should be very helpful. I took a quick look: you should set Modifier.requiredSize() on the Image, otherwise it may be zero size. However, that is not enough: the crash persists.

You can use ViewCompositionStrategy.DisposeOnDetachedFromWindow on your Map Fragment composition to work around the issue; this will dispose the composition a lot more than before, though: I think it will essentially dispose the composition whenever the fragment is not current in the pager.

Here is the stacktrace:

java.lang.IllegalStateException: The ComposeView was measured to have a width or height of zero. Make sure that the content has a non-zero size.
	at com.google.maps.android.compose.RememberComposeBitmapDescriptorKt.renderComposableToBitmapDescriptor(RememberComposeBitmapDescriptor.kt:58)
	at com.google.maps.android.compose.RememberComposeBitmapDescriptorKt.access$renderComposableToBitmapDescriptor(RememberComposeBitmapDescriptor.kt:1)
	at com.google.maps.android.compose.RememberComposeBitmapDescriptorKt.rememberComposeBitmapDescriptor(RememberComposeBitmapDescriptor.kt:29)
	at com.google.maps.android.compose.MarkerKt.MarkerComposable-Khg_OnI(Marker.kt:313)
	at code.bug.map.ComposeMapFragmentKt$MapWithMarker$1.invoke(ComposeMapFragment.kt:55)
	at code.bug.map.ComposeMapFragmentKt$MapWithMarker$1.invoke(ComposeMapFragment.kt:53)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:109)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:35)
	at androidx.compose.runtime.RecomposeScopeImpl.compose(RecomposeScopeImpl.kt:192)
	at androidx.compose.runtime.ComposerImpl.recomposeToGroupEnd(Composer.kt:2825)
	at androidx.compose.runtime.ComposerImpl.skipCurrentGroup(Composer.kt:3116)
	at androidx.compose.runtime.ComposerImpl.doCompose(Composer.kt:3607)
	at androidx.compose.runtime.ComposerImpl.recompose$runtime_release(Composer.kt:3552)
	at androidx.compose.runtime.CompositionImpl.recompose(Composition.kt:948)
	at androidx.compose.runtime.Recomposer.performRecompose(Recomposer.kt:1206)
	at androidx.compose.runtime.Recomposer.access$performRecompose(Recomposer.kt:132)
	at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$1.invoke(Recomposer.kt:616)
	at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$1.invoke(Recomposer.kt:585)
	at androidx.compose.ui.platform.AndroidUiFrameClock$withFrameNanos$2$callback$1.doFrame(AndroidUiFrameClock.android.kt:41)
	at androidx.compose.ui.platform.AndroidUiDispatcher.performFrameDispatch(AndroidUiDispatcher.android.kt:109)
	at androidx.compose.ui.platform.AndroidUiDispatcher.access$performFrameDispatch(AndroidUiDispatcher.android.kt:41)
	at androidx.compose.ui.platform.AndroidUiDispatcher$dispatchCallback$1.doFrame(AndroidUiDispatcher.android.kt:69)
	at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1564)
	at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1575)
	at android.view.Choreographer.doCallbacks(Choreographer.java:1175)
	at android.view.Choreographer.doFrame(Choreographer.java:1100)
	at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1549)
	at android.os.Handler.handleCallback(Handler.java:991)
	at android.os.Handler.dispatchMessage(Handler.java:102)
	at android.os.Looper.loopOnce(Looper.java:232)
	at android.os.Looper.loop(Looper.java:317)
	at android.app.ActivityThread.main(ActivityThread.java:8875)
	at java.lang.reflect.Method.invoke(Native Method)
	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:591)
	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:891)
	Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [androidx.compose.runtime.PausableMonotonicFrameClock@4c218af, androidx.compose.ui.platform.MotionDurationScaleImpl@8404bc, StandaloneCoroutine{Cancelling}@70f7c45, AndroidUiDispatcher@bd31f9a]

The ComposeView is zero measured size here, presumably due to the Fragment View not currently being displayed on the screen.

A maintainer may need to address this, I'm not sure how to best fix it; I'm no expert on the Android View system.

My thinking is, if the ComposeView cannot be forced to the size we want when the parent View is zero size, then we should not use the parent. We could draw into some sort of offline View, but we'd lose all inherited "attributes" from the parent View, including View attributes and Compose attributes. It may be sufficient to install the CompositionContext from the parent View on the offline View composition to preserve Compose attributes, but not sure how to preserve View attributes, or if that is necessary.

Also, additional work may be needed for the clustering case, it uses a more sophisticated approach for certain things.

@ln-12
Copy link
Contributor

ln-12 commented Jan 3, 2025

@bubenheimer Thanks for looking into this topic again!

You mention the use of the requiredSize modifier. As I also found out above, this is not enough to fix the crash.
From a user/consumer perspective, I think that the min required size (of 1x1) should be handled within the MarkerComposable itself as it is specific to the internal implementation and easy to misuse/forget.

@Abdelsattar
Copy link

Thanks @mariohide for sharing this workaround, I have used it and it worked until we can get a propre soultion from Maps.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
triage me I really want to be triaged. type: feature request ‘Nice-to-have’ improvement, new feature or different behavior or design.
Projects
None yet
Development

No branches or pull requests

5 participants