aster.cloud aster.cloud
  • /
  • Platforms
    • Public Cloud
    • On-Premise
    • Hybrid Cloud
    • Data
  • Architecture
    • Design
    • Solutions
    • Enterprise
  • Engineering
    • Automation
    • Software Engineering
    • Project Management
    • DevOps
  • Programming
    • Learning
  • Tools
  • About
  • /
  • Platforms
    • Public Cloud
    • On-Premise
    • Hybrid Cloud
    • Data
  • Architecture
    • Design
    • Solutions
    • Enterprise
  • Engineering
    • Automation
    • Software Engineering
    • Project Management
    • DevOps
  • Programming
    • Learning
  • Tools
  • About
aster.cloud aster.cloud
  • /
  • Platforms
    • Public Cloud
    • On-Premise
    • Hybrid Cloud
    • Data
  • Architecture
    • Design
    • Solutions
    • Enterprise
  • Engineering
    • Automation
    • Software Engineering
    • Project Management
    • DevOps
  • Programming
    • Learning
  • Tools
  • About
  • Programming

Diving Into Compose — Lessons Learned While Building Maps Compose

  • aster.cloud
  • June 6, 2022
  • 7 minute read

Interoperability and Compose API lessons learned while building Maps Compose

This year we released the Maps Compose library, a Jetpack Compose library for adding Google Maps to your app. At its core, Maps Compose is an interop library for the Maps SDK for Android that exposes Compose friendly APIs. So, to create the composable elements of Maps Compose we needed to work under the constraints of the existing API of the Maps SDK, and the available Compose interop functions.

Maps Compose went through a couple of design and implementation iterations before eventually landing the initial release. In this blog post, I’d like to cover the background around Maps Compose, how it came to be, and some lessons learned while working on it. This post is particularly relevant to SDK developers wanting to provide Compose support; however, it should also be relevant for the Compose-curious readers out there. If you fall into one of those buckets — read on!


Partner with aster.cloud
for your next big idea.
Let us know here.



From our partners:

CITI.IO :: Business. Institutions. Society. Global Political Economy.
CYBERPOGO.COM :: For the Arts, Sciences, and Technology.
DADAHACKS.COM :: Parenting For The Rest Of Us.
ZEDISTA.COM :: Entertainment. Sports. Culture. Escape.
TAKUMAKU.COM :: For The Hearth And Home.
ASTER.CLOUD :: From The Cloud And Beyond.
LIWAIWAI.COM :: Intelligence, Inside and Outside.
GLOBALCLOUDPLATFORMS.COM :: For The World's Computing Needs.
FIREGULAMAN.COM :: For The Fire In The Belly Of The Coder.
ASTERCASTER.COM :: Supra Astra. Beyond The Stars.
BARTDAY.COM :: Prosperity For Everyone.

Background

Before Maps Compose was available, using the Maps SDK in Compose was already possible thanks to Compose’s interoperability APIs, namely, the AndroidView composable. Simple use cases — like showing a map with a single marker on it — were straightforward; however, moderately complex integrations with lots of customizations and drawings required writing a lot of interop code, making usage not as straightforward.

To get a gauge on how useful a Compose library might be for Android developers, I tweeted the following:

Preview API of Maps Compose.

To my surprise, a lot of developers responded with statements like “Yes, please!”, “Cool!”, and “This would replace a few hundred lines of code.” 🤯 As one of the Developer Relations Engineers working on the Maps SDK at the time, it made sense to prioritize releasing composable elements for the Maps SDK. From there, I internally proposed a design and implementation for Maps Compose and collaborated with Adam Powell, Leland Richardson, and Ben Trengrove to get it to the finish line.

Giving feedback makes a difference and translates to real product changes. We love hearing from you!

Lessons Learned

Lesson #1: Reuse classes in the core Maps SDK

The Maps SDK has been around for 10+ years and is used by many apps. While Compose introduces a completely different way of building UI, a composable version of maps should still feel familiar. If you know a bit of Compose, and have used the Maps SDK before, composable maps should be intuitive for you.

To help make the API intuitive, we reused the underlying Maps SDK classes when possible. For example, to perform camera updates in Maps Compose, you can still use the existing CameraUpdate class created from the CameraUpdateFactory object.

Read More  Jetpack Compose: Debugging Recomposition

There were some instances, however, when the existing classes in the Maps SDK couldn’t be used as-is. For example, the UiSettings class did not make sense to be reused since it can only be retrieved once the map has been created. Ideally, you should be able to create an instance of this class and be able to pass it into the GoogleMap composable. To work around this, the class was mirrored to a Maps Compose type, MapUiSettings. The naming closely matches the existing UiSettings class with the additional “Map” prefix to help with discoverability of the API. MapUiSettings has the same exact properties and default values as UiSettings, the difference being that it can be created and passed into the GoogleMap composable as opposed to obtaining and mutating it from another control surface:

// Copyright 2022 Google LLC.	
// SPDX-License-Identifier: Apache-2.0

GoogleMap(
  uiSettings = MapUiSettings(compassEnabled = false, mapToolbarEnabled = true)
  // …
)

There are other properties of the map that can be changed at runtime (for example, setBuildingsEnabled(boolean)). One consideration we had was to expose these properties as individual parameters on the GoogleMap composable; however, that would significantly increase the number of parameters since there are a lot of properties that can be toggled. Instead, we opted to create a separate class, MapProperties, which contains these runtime-configured properties:

// Copyright 2022 Google LLC.	
// SPDX-License-Identifier: Apache-2.0

GoogleMap(
  properties = MapProperties(isBuildingEnabled = true)
  // …
)

For objects that can be drawn on the map (markers, polylines, etc.), the imperative View-based approach is to call add* methods like GoogleMap.addMarker(MarkerOptions) on the GoogleMap object. To convert this in Compose, the GoogleMap composable could accept a list parameter for each drawing, however, this API could be difficult to use for integrations that contain a lot of drawn objects with complex logic. Instead, we decided to expose a Compose friendly API — a generic content lambda wherein drawings can be invoked as separate composables.

Need to draw a marker, polyline, or other supported drawn object on the map? Call the Marker, Polyline, or another decorator composable function in the content lambda of the GoogleMap composable like so:

// Copyright 2022 Google LLC.	
// SPDX-License-Identifier: Apache-2.0

GoogleMap(modifier = Modifier.fillMaxSize()) {
  Marker(
    state = MarkerState(LatLng(1.35, 103.87)),
    title = "Marker in Singapore",
    onClick = { Log.d("Marker", "Marker was clicked") }
  )
}

Lesson #2: Take advantage of Kotlin features

The Maps SDK was built at a time before Kotlin was a first-class language for writing Android apps. That said, the Maps SDK is largely built in Java. Jetpack Compose on the other hand, is entirely written in Kotlin and heavily leans on Kotlin idioms. For Maps Compose, we also decided to lean in on Kotlin language features like coroutines to expose a Kotlin idiomatic API.

Read More  Spot Your UI Jank Using CPU Profiler In Android Studio

For instance, Compose uses Kotlin’s coroutine suspending functions for animation APIs. So, it made sense to provide a similar API for the underlying callback-based APIs in the Maps SDK. For example, animating the camera and waiting for it to complete can be done within a coroutine scope:

// Copyright 2022 Google LLC.	
// SPDX-License-Identifier: Apache-2.0

val singapore = LatLng(1.35, 103.87)
val cameraPositionState = rememberCameraPositionState {
   position = CameraPosition.fromLatLngZoom(singapore, 11f)
}
Box(Modifier.fillMaxSize()) {
   GoogleMap(
       modifier = Modifier.matchParentSize(),
       cameraPositionState = cameraPositionState
   )
   val coroutineScope = rememberCoroutineScope()
   Button(onClick = {
       coroutineScope.launch {
           cameraPositionState.animate(
               CameraUpdateFactory.zoomIn()
           )
       }
   }) {
       Text(text = "Zoom in")
   }
}

For a list of other Kotlin idioms widely used in Compose, see Kotlin for Jetpack Compose.

Lesson #3: Maintain consistency with other Compose toolkit APIs

Maintaining consistency with other Compose toolkit APIs enables good developer ergonomics. Doing so allows functions to be easier to use, and thus faster to develop with, as it follows a familiar convention with other APIs. Whether you are a library or app developer, this consistency is essential to promote ease-of-use. The Compose API guidelines is an excellent resource for learning conventions followed by Compose APIs.

Here are a few patterns outlined in the guidelines that Maps Compose adopts:

  • The GoogleMap composable complies with Elements accept and respect a Modifier parameter.
  • The MarkerInfoWindow composable complies with this point listed under Compose UI Layouts: “Layout functions should place their primary or most common @Composable function parameter [this should be named content] in the last position to permit the use of Kotlin’s trailing lambda syntax”.

There have been a couple of instances where my initial designs differed from these guidelines, and I found it very helpful to refer to them to adjust the API decisions to better align with Compose best practices.

Lesson #4: Plain classes are best for binary compatibility

Kotlin data classes are an efficient way to hold data. They offer a handful of generated methods that you don’t have to write yourself, saving you several lines of code per class. However, if you’re writing a library, data classes have a hidden cost as future changes to the data class break binary compatibility. Adding new properties will change the generated method signature for copy(), and depending on where the new property was added, it could also break destructuring functions thereby breaking consumers. To mitigate this, Maps Compose uses plain classes for MapUiSetting and MapProperties. Hat tip to Jake Wharton for pointing this out in his Public API challenges in Kotlin blog post.

Read More  Faster Jetpack Compose View Interop With App Startup And Baseline Profile

Lesson #5: Use Compose common types

To customize colors of a drawn object in the Maps SDK, you provide it a color integer. For example, to customize a Circle’s fill color you provide it a color integer when constructing the CircleOptions object. The Maps Compose Circle on the other hand, uses the Compose provided Color class instead.

// Copyright 2022 Google LLC.	
// SPDX-License-Identifier: Apache-2.0

MyAppTheme {
   GoogleMap(
       //…
   ) {
       Circle(
           center = singapore,
           fillColor = MaterialTheme.colors.primary
       )
   }
}

One of the awesome features of Compose is its built-in support for applying material theming to your app. So by using the Compose provided Color class, when the GoogleMap and its children composables are used within a MaterialTheme, the colors automatically adapt to your theme’s colors when the system appearance changes to either light or dark mode.

Lesson #6: Subcompositions are powerful

Early in the development process, we identified that adding and removing map decorations using side effect APIs over time to match the app’s data model was tedious and error prone. The need to manage a tree of elements is effectively the same problem as managing a composable UI tree, and so a better solution would be to use the same underlying tooling for directly updating the elements as state changes over time. This approach turned out to be a lot more straightforward and intuitive over using side effects.

To achieve this, we used the Applier class and the ComposeNode composable to support the child-based API (content lambda) of adding drawn objects (markers, polylines, polygons, etc.) on the map. The resulting implementation creates a new subcomposition that manages the map’s state instead of Compose UI nodes.

Taking a marker as an example, with subcomposition we are able to ensure that the map’s state is updated as recomposition occurs. So for example, if a Marker composable was previously in the composition and was later removed, we can tap into the appropriate node removal method to ensure the underlying Marker Maps SDK object is also removed from the map.

If you want to dig into the code, check out the implementation of MapApplier and Marker to learn more about how to use these APIs.

Conclusion

Overall, I was impressed at how the available Compose interop APIs made supporting the Maps SDK in Compose doable. While a native implementation of the Maps SDK is to-be desired, Maps Compose bridges the gap for many Maps developers using Compose.

Hopefully you found this post insightful and learned a thing or two about designing Compose APIs and making Compose work with existing View code.

If you’re new to Compose or Maps Compose, check out the sample apps to learn more:

  • Compose samples
  • Maps Compose sample

If there’s anything you’d like to see next, let me know and leave a comment below!

By Chris Arriola
Source Medium


For enquiries, product placements, sponsorships, and collaborations, connect with us at [email protected]. We'd love to hear from you!

Our humans need coffee too! Your support is highly appreciated, thank you!

aster.cloud

Related Topics
  • Compose
  • GoogleMap
  • Jetpack Compose
  • UiSettings
You May Also Like
View Post
  • Architecture
  • Data
  • Engineering
  • People
  • Programming
  • Software Engineering
  • Technology
  • Work & Jobs

Predictions: Top 25 Careers Likely In High Demand In The Future

  • June 6, 2023
View Post
  • Programming
  • Software Engineering
  • Technology

Build a Python App to Alert You When Asteroids Are Close to Earth

  • May 22, 2023
View Post
  • Programming

Illuminating Interactions: Visual State In Jetpack Compose

  • May 20, 2023
View Post
  • Computing
  • Data
  • Programming
  • Software
  • Software Engineering

The Top 10 Data Interchange Or Data Exchange Format Used Today

  • May 11, 2023
View Post
  • Architecture
  • Programming
  • Public Cloud

From Receipts To Riches: Save Money W/ Google Cloud & Supermarket Bills – Part 1

  • May 8, 2023
View Post
  • Programming
  • Public Cloud

3 New Ways To Authorize Users To Your Private Workloads On Cloud Run

  • May 4, 2023
View Post
  • Programming
  • Public Cloud

Buffer HTTP Requests With Cloud Tasks

  • May 4, 2023
View Post
  • Programming
  • Public Cloud
  • Software
  • Software Engineering

Learn About Google Cloud’s Updated Renderer For The Maps SDK For Android

  • May 4, 2023

Stay Connected!
LATEST
  • Send SMS texts with Amazon’s SNS simple notification service
    • July 1, 2025
  • Camping 2
    The Summer Adventures : Camping Essentials
    • June 27, 2025
  • Host a static website on AWS with Amazon S3 and Route 53
    • June 27, 2025
  • Prioritize security from the edge to the cloud
    • June 25, 2025
  • 6 edge monitoring best practices in the cloud
    • June 25, 2025
  • Genome 6
    AlphaGenome: AI for better understanding the genome
    • June 25, 2025
  • 7
    Pure Accelerate 2025: All the news and updates live from Las Vegas
    • June 18, 2025
  • 8
    ‘This was a very purposeful strategy’: Pure Storage unveils Enterprise Data Cloud in bid to unify data storage, management
    • June 18, 2025
  • What is cloud bursting?
    • June 18, 2025
  • 10
    There’s a ‘cloud reset’ underway, and VMware Cloud Foundation 9.0 is a chance for Broadcom to pounce on it
    • June 17, 2025
about
Hello World!

We are aster.cloud. We’re created by programmers for programmers.

Our site aims to provide guides, programming tips, reviews, and interesting materials for tech people and those who want to learn in general.

We would like to hear from you.

If you have any feedback, enquiries, or sponsorship request, kindly reach out to us at:

[email protected]
Most Popular
  • Oracle adds xAI Grok models to OCI
    • June 17, 2025
  • What is confidential computing?
    • June 17, 2025
  • Fine-tune your storage-as-a-service approach
    • June 16, 2025
  • 4
    Advanced audio dialog and generation with Gemini 2.5
    • June 15, 2025
  • Google Cloud, Cloudflare struck by widespread outages
    • June 12, 2025
  • /
  • Technology
  • Tools
  • About
  • Contact Us

Input your search keywords and press Enter.