@@ -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
@@ -109,101 +111,116 @@ public fun GoogleMap(
109111 return
110112 }
111113
112- // rememberUpdatedState and friends are used here to make these values observable to
113- // the subcomposition without providing a new content function each recomposition
114- val mapClickListeners = remember { MapClickListeners () }.also {
115- it.indoorStateChangeListener = indoorStateChangeListener
116- it.onMapClick = onMapClick
117- it.onMapLongClick = onMapLongClick
118- it.onMapLoaded = onMapLoaded
119- it.onMyLocationButtonClick = onMyLocationButtonClick
120- it.onMyLocationClick = onMyLocationClick
121- it.onPOIClick = onPOIClick
122- }
114+ val isInitialized by MapsApiAttribution .isInitialized
123115
124- val mapUpdaterState = remember {
125- MapUpdaterState (
126- mergeDescendants,
127- contentDescription,
128- cameraPositionState,
129- contentPadding,
130- locationSource,
131- properties,
132- uiSettings,
133- mapColorScheme?.value,
134- )
135- }.also {
136- it.mergeDescendants = mergeDescendants
137- it.contentDescription = contentDescription
138- it.cameraPositionState = cameraPositionState
139- it.contentPadding = contentPadding
140- it.locationSource = locationSource
141- it.mapProperties = properties
142- it.mapUiSettings = uiSettings
143- it.mapColorScheme = mapColorScheme?.value
116+ if (! isInitialized) {
117+ val context = LocalContext .current
118+ LaunchedEffect (Unit ) {
119+ MapsApiAttribution .addAttributionId(context)
120+ }
144121 }
145122
146- val parentComposition = rememberCompositionContext()
147- val currentContent by rememberUpdatedState(content)
148- var subcompositionJob by remember { mutableStateOf<Job ?>(null ) }
149- val parentCompositionScope = rememberCoroutineScope()
150-
151- AndroidView (
152- modifier = modifier,
153- factory = { context ->
154- MapView (context, googleMapOptionsFactory()) .also { mapView ->
155- MapsApiSettings .addInternalUsageAttributionId(context, AttributionId .VALUE )
156- val componentCallbacks = object : ComponentCallbacks2 {
157- override fun onConfigurationChanged (newConfig : Configuration ) {}
158- @Deprecated(" Deprecated in Java" , ReplaceWith (" onTrimMemory(level)" ))
159- override fun onLowMemory () { mapView.onLowMemory() }
160- override fun onTrimMemory (level : Int ) { mapView.onLowMemory() }
161- }
162- context.registerComponentCallbacks(componentCallbacks)
163-
164- val lifecycleObserver = MapLifecycleEventObserver (mapView)
123+ if (isInitialized) {
124+ // rememberUpdatedState and friends are used here to make these values observable to
125+ // the subcomposition without providing a new content function each recomposition
126+ val mapClickListeners = remember { MapClickListeners () }.also {
127+ it.indoorStateChangeListener = indoorStateChangeListener
128+ it.onMapClick = onMapClick
129+ it.onMapLongClick = onMapLongClick
130+ it.onMapLoaded = onMapLoaded
131+ it.onMyLocationButtonClick = onMyLocationButtonClick
132+ it.onMyLocationClick = onMyLocationClick
133+ it.onPOIClick = onPOIClick
134+ }
165135
166- mapView.tag = MapTagData (componentCallbacks, lifecycleObserver)
136+ val mapUpdaterState = remember {
137+ MapUpdaterState (
138+ mergeDescendants,
139+ contentDescription,
140+ cameraPositionState,
141+ contentPadding,
142+ locationSource,
143+ properties,
144+ uiSettings,
145+ mapColorScheme?.value,
146+ )
147+ }.also {
148+ it.mergeDescendants = mergeDescendants
149+ it.contentDescription = contentDescription
150+ it.cameraPositionState = cameraPositionState
151+ it.contentPadding = contentPadding
152+ it.locationSource = locationSource
153+ it.mapProperties = properties
154+ it.mapUiSettings = uiSettings
155+ it.mapColorScheme = mapColorScheme?.value
156+ }
167157
168- // Only register for [lifecycleOwner]'s lifecycle events while MapView is attached
169- val onAttachStateListener = object : View .OnAttachStateChangeListener {
170- private var lifecycle: Lifecycle ? = null
158+ val parentComposition = rememberCompositionContext()
159+ val currentContent by rememberUpdatedState(content)
160+ var subcompositionJob by remember { mutableStateOf<Job ?>(null ) }
161+ val parentCompositionScope = rememberCoroutineScope()
162+
163+ AndroidView (
164+ modifier = modifier,
165+ factory = { context ->
166+ MapView (context, googleMapOptionsFactory()).also { mapView ->
167+ val componentCallbacks = object : ComponentCallbacks2 {
168+ override fun onConfigurationChanged (newConfig : Configuration ) {}
169+
170+ @Deprecated(" Deprecated in Java" , ReplaceWith (" onTrimMemory(level)" ))
171+ override fun onLowMemory () {
172+ mapView.onLowMemory()
173+ }
171174
172- override fun onViewAttachedToWindow (mapView : View ) {
173- lifecycle = mapView.findViewTreeLifecycleOwner()!! .lifecycle.also {
174- it.addObserver(lifecycleObserver)
175+ override fun onTrimMemory (level : Int ) {
176+ mapView.onLowMemory()
175177 }
176178 }
179+ context.registerComponentCallbacks(componentCallbacks)
180+
181+ val lifecycleObserver = MapLifecycleEventObserver (mapView)
182+
183+ mapView.tag = MapTagData (componentCallbacks, lifecycleObserver)
184+
185+ // Only register for [lifecycleOwner]'s lifecycle events while MapView is attached
186+ val onAttachStateListener = object : View .OnAttachStateChangeListener {
187+ private var lifecycle: Lifecycle ? = null
177188
178- override fun onViewDetachedFromWindow (v : View ) {
179- lifecycle?.removeObserver(lifecycleObserver)
180- lifecycle = null
181- lifecycleObserver.moveToBaseState()
189+ override fun onViewAttachedToWindow (mapView : View ) {
190+ lifecycle = mapView.findViewTreeLifecycleOwner()!! .lifecycle.also {
191+ it.addObserver(lifecycleObserver)
192+ }
193+ }
194+
195+ override fun onViewDetachedFromWindow (v : View ) {
196+ lifecycle?.removeObserver(lifecycleObserver)
197+ lifecycle = null
198+ lifecycleObserver.moveToBaseState()
199+ }
182200 }
183- }
184201
185- mapView.addOnAttachStateChangeListener(onAttachStateListener)
186- }
187- },
188- onReset = { /* View is detached. */ },
189- onRelease = { mapView ->
190- val (componentCallbacks, lifecycleObserver) = mapView.tagData
191- mapView.context.unregisterComponentCallbacks(componentCallbacks)
192- lifecycleObserver.moveToDestroyedState()
193- mapView.tag = null
194- },
195- update = { mapView ->
196- if (subcompositionJob == null ) {
197- subcompositionJob = parentCompositionScope.launchSubcomposition(
198- mapUpdaterState,
199- parentComposition,
200- mapView,
201- mapClickListeners,
202- currentContent,
203- )
204- }
205- }
206- )
202+ mapView.addOnAttachStateChangeListener(onAttachStateListener)
203+ }
204+ },
205+ onReset = { /* View is detached. */ },
206+ onRelease = { mapView ->
207+ val (componentCallbacks, lifecycleObserver) = mapView.tagData
208+ mapView.context.unregisterComponentCallbacks(componentCallbacks)
209+ lifecycleObserver.moveToDestroyedState()
210+ mapView.tag = null
211+ },
212+ update = { mapView ->
213+ if (subcompositionJob == null ) {
214+ subcompositionJob = parentCompositionScope.launchSubcomposition(
215+ mapUpdaterState,
216+ parentComposition,
217+ mapView,
218+ mapClickListeners,
219+ currentContent,
220+ )
221+ }
222+ })
223+ }
207224}
208225
209226/* *
0 commit comments