@@ -26,6 +26,7 @@ import androidx.compose.runtime.Composable
2626import androidx.compose.runtime.Composition
2727import androidx.compose.runtime.CompositionContext
2828import androidx.compose.runtime.CompositionLocalProvider
29+ import androidx.compose.runtime.LaunchedEffect
2930import androidx.compose.runtime.Stable
3031import androidx.compose.runtime.getValue
3132import androidx.compose.runtime.mutableStateOf
@@ -35,6 +36,7 @@ import androidx.compose.runtime.rememberCoroutineScope
3536import androidx.compose.runtime.rememberUpdatedState
3637import androidx.compose.runtime.setValue
3738import androidx.compose.ui.Modifier
39+ import androidx.compose.ui.platform.LocalContext
3840import androidx.compose.ui.platform.LocalInspectionMode
3941import androidx.compose.ui.viewinterop.AndroidView
4042import androidx.lifecycle.Lifecycle
@@ -44,11 +46,11 @@ import androidx.lifecycle.findViewTreeLifecycleOwner
4446import com.google.android.gms.maps.GoogleMapOptions
4547import com.google.android.gms.maps.LocationSource
4648import com.google.android.gms.maps.MapView
47- import com.google.android.gms.maps.MapsApiSettings
4849
4950import com.google.android.gms.maps.model.LatLng
5051import com.google.android.gms.maps.model.MapColorScheme
5152import com.google.android.gms.maps.model.PointOfInterest
53+ import com.google.maps.android.compose.internal.MapsApiAttribution
5254import com.google.maps.android.compose.meta.AttributionId
5355import com.google.maps.android.ktx.awaitMap
5456import kotlinx.coroutines.CoroutineScope
@@ -110,101 +112,116 @@ public fun GoogleMap(
110112 return
111113 }
112114
113- // rememberUpdatedState and friends are used here to make these values observable to
114- // the subcomposition without providing a new content function each recomposition
115- val mapClickListeners = remember { MapClickListeners () }.also {
116- it.indoorStateChangeListener = indoorStateChangeListener
117- it.onMapClick = onMapClick
118- it.onMapLongClick = onMapLongClick
119- it.onMapLoaded = onMapLoaded
120- it.onMyLocationButtonClick = onMyLocationButtonClick
121- it.onMyLocationClick = onMyLocationClick
122- it.onPOIClick = onPOIClick
123- }
115+ val isInitialized by MapsApiAttribution .isInitialized
124116
125- val mapUpdaterState = remember {
126- MapUpdaterState (
127- mergeDescendants,
128- contentDescription,
129- cameraPositionState,
130- contentPadding,
131- locationSource,
132- properties,
133- uiSettings,
134- mapColorScheme?.value,
135- )
136- }.also {
137- it.mergeDescendants = mergeDescendants
138- it.contentDescription = contentDescription
139- it.cameraPositionState = cameraPositionState
140- it.contentPadding = contentPadding
141- it.locationSource = locationSource
142- it.mapProperties = properties
143- it.mapUiSettings = uiSettings
144- it.mapColorScheme = mapColorScheme?.value
117+ if (! isInitialized) {
118+ val context = LocalContext .current
119+ LaunchedEffect (Unit ) {
120+ MapsApiAttribution .addAttributionId(context)
121+ }
145122 }
146123
147- val parentComposition = rememberCompositionContext()
148- val currentContent by rememberUpdatedState(content)
149- var subcompositionJob by remember { mutableStateOf<Job ?>(null ) }
150- val parentCompositionScope = rememberCoroutineScope()
151-
152- AndroidView (
153- modifier = modifier,
154- factory = { context ->
155- MapView (context, googleMapOptionsFactory()) .also { mapView ->
156- MapsApiSettings .addInternalUsageAttributionId(context, AttributionId .VALUE )
157- val componentCallbacks = object : ComponentCallbacks2 {
158- override fun onConfigurationChanged (newConfig : Configuration ) {}
159- @Deprecated(" Deprecated in Java" , ReplaceWith (" onTrimMemory(level)" ))
160- override fun onLowMemory () { mapView.onLowMemory() }
161- override fun onTrimMemory (level : Int ) { mapView.onLowMemory() }
162- }
163- context.registerComponentCallbacks(componentCallbacks)
164-
165- val lifecycleObserver = MapLifecycleEventObserver (mapView)
124+ if (isInitialized) {
125+ // rememberUpdatedState and friends are used here to make these values observable to
126+ // the subcomposition without providing a new content function each recomposition
127+ val mapClickListeners = remember { MapClickListeners () }.also {
128+ it.indoorStateChangeListener = indoorStateChangeListener
129+ it.onMapClick = onMapClick
130+ it.onMapLongClick = onMapLongClick
131+ it.onMapLoaded = onMapLoaded
132+ it.onMyLocationButtonClick = onMyLocationButtonClick
133+ it.onMyLocationClick = onMyLocationClick
134+ it.onPOIClick = onPOIClick
135+ }
166136
167- mapView.tag = MapTagData (componentCallbacks, lifecycleObserver)
137+ val mapUpdaterState = remember {
138+ MapUpdaterState (
139+ mergeDescendants,
140+ contentDescription,
141+ cameraPositionState,
142+ contentPadding,
143+ locationSource,
144+ properties,
145+ uiSettings,
146+ mapColorScheme?.value,
147+ )
148+ }.also {
149+ it.mergeDescendants = mergeDescendants
150+ it.contentDescription = contentDescription
151+ it.cameraPositionState = cameraPositionState
152+ it.contentPadding = contentPadding
153+ it.locationSource = locationSource
154+ it.mapProperties = properties
155+ it.mapUiSettings = uiSettings
156+ it.mapColorScheme = mapColorScheme?.value
157+ }
168158
169- // Only register for [lifecycleOwner]'s lifecycle events while MapView is attached
170- val onAttachStateListener = object : View .OnAttachStateChangeListener {
171- private var lifecycle: Lifecycle ? = null
159+ val parentComposition = rememberCompositionContext()
160+ val currentContent by rememberUpdatedState(content)
161+ var subcompositionJob by remember { mutableStateOf<Job ?>(null ) }
162+ val parentCompositionScope = rememberCoroutineScope()
163+
164+ AndroidView (
165+ modifier = modifier,
166+ factory = { context ->
167+ MapView (context, googleMapOptionsFactory()).also { mapView ->
168+ val componentCallbacks = object : ComponentCallbacks2 {
169+ override fun onConfigurationChanged (newConfig : Configuration ) {}
170+
171+ @Deprecated(" Deprecated in Java" , ReplaceWith (" onTrimMemory(level)" ))
172+ override fun onLowMemory () {
173+ mapView.onLowMemory()
174+ }
172175
173- override fun onViewAttachedToWindow (mapView : View ) {
174- lifecycle = mapView.findViewTreeLifecycleOwner()!! .lifecycle.also {
175- it.addObserver(lifecycleObserver)
176+ override fun onTrimMemory (level : Int ) {
177+ mapView.onLowMemory()
176178 }
177179 }
180+ context.registerComponentCallbacks(componentCallbacks)
181+
182+ val lifecycleObserver = MapLifecycleEventObserver (mapView)
183+
184+ mapView.tag = MapTagData (componentCallbacks, lifecycleObserver)
185+
186+ // Only register for [lifecycleOwner]'s lifecycle events while MapView is attached
187+ val onAttachStateListener = object : View .OnAttachStateChangeListener {
188+ private var lifecycle: Lifecycle ? = null
178189
179- override fun onViewDetachedFromWindow (v : View ) {
180- lifecycle?.removeObserver(lifecycleObserver)
181- lifecycle = null
182- lifecycleObserver.moveToBaseState()
190+ override fun onViewAttachedToWindow (mapView : View ) {
191+ lifecycle = mapView.findViewTreeLifecycleOwner()!! .lifecycle.also {
192+ it.addObserver(lifecycleObserver)
193+ }
194+ }
195+
196+ override fun onViewDetachedFromWindow (v : View ) {
197+ lifecycle?.removeObserver(lifecycleObserver)
198+ lifecycle = null
199+ lifecycleObserver.moveToBaseState()
200+ }
183201 }
184- }
185202
186- mapView.addOnAttachStateChangeListener(onAttachStateListener)
187- }
188- },
189- onReset = { /* View is detached. */ },
190- onRelease = { mapView ->
191- val (componentCallbacks, lifecycleObserver) = mapView.tagData
192- mapView.context.unregisterComponentCallbacks(componentCallbacks)
193- lifecycleObserver.moveToDestroyedState()
194- mapView.tag = null
195- },
196- update = { mapView ->
197- if (subcompositionJob == null ) {
198- subcompositionJob = parentCompositionScope.launchSubcomposition(
199- mapUpdaterState,
200- parentComposition,
201- mapView,
202- mapClickListeners,
203- currentContent,
204- )
205- }
206- }
207- )
203+ mapView.addOnAttachStateChangeListener(onAttachStateListener)
204+ }
205+ },
206+ onReset = { /* View is detached. */ },
207+ onRelease = { mapView ->
208+ val (componentCallbacks, lifecycleObserver) = mapView.tagData
209+ mapView.context.unregisterComponentCallbacks(componentCallbacks)
210+ lifecycleObserver.moveToDestroyedState()
211+ mapView.tag = null
212+ },
213+ update = { mapView ->
214+ if (subcompositionJob == null ) {
215+ subcompositionJob = parentCompositionScope.launchSubcomposition(
216+ mapUpdaterState,
217+ parentComposition,
218+ mapView,
219+ mapClickListeners,
220+ currentContent,
221+ )
222+ }
223+ })
224+ }
208225}
209226
210227/* *
0 commit comments