Interoperability and Compose API classes discovered whereas constructing Maps Compose
This yr we launched the Maps Compose library, a Jetpack Compose library for including Google Maps to your app. At its core, Maps Compose is an interop library for the Maps SDK for Android that exposes Compose pleasant APIs. So, to create the composable components of Maps Compose we would have liked to work underneath the constraints of the present API of the Maps SDK, and the obtainable Compose interop capabilities.
Maps Compose went by a few design and implementation iterations earlier than ultimately touchdown the preliminary launch. On this weblog submit, I’d wish to cowl the background round Maps Compose, the way it got here to be, and a few classes discovered whereas engaged on it. This submit is especially related to SDK builders wanting to supply Compose help; nonetheless, it also needs to be related for the Compose-curious readers on the market. Should you fall into a type of buckets — learn on!
Earlier than Maps Compose was obtainable, utilizing the Maps SDK in Compose was already potential due to Compose’s interoperability APIs, particularly, the AndroidView composable. Easy use circumstances — like displaying a map with a single marker on it — have been easy; nonetheless, reasonably complicated integrations with numerous customizations and drawings required writing plenty of interop code, making utilization not as easy.
To get a gauge on how helpful a Compose library may be for Android builders, I tweeted the next:
To my shock, plenty of builders responded with statements like “Sure, please!”, “Cool!”, and “This may exchange a number of hundred traces of code.” 🤯 As one of many Developer Relations Engineers engaged on the Maps SDK on the time, it made sense to prioritize releasing composable components 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 end line.
Giving suggestions makes a distinction and interprets to actual product modifications. We love listening to from you!
Lesson #1: Reuse courses within the core Maps SDK
The Maps SDK has been round for 10+ years and is utilized by many apps. Whereas Compose introduces a very totally different means of constructing UI, a composable model of maps ought to nonetheless really feel acquainted. If you realize a little bit of Compose, and have used the Maps SDK earlier than, composable maps ought to be intuitive for you.
To assist make the API intuitive, we reused the underlying Maps SDK courses when potential. For instance, to carry out digital camera updates in Maps Compose, you’ll be able to nonetheless use the present CameraUpdate class created from the CameraUpdateFactory object.
There have been some situations, nonetheless, when the present courses within the Maps SDK couldn’t be used as-is. For instance, the UiSettings class didn’t make sense to be reused since it could solely be retrieved as soon as the map has been created. Ideally, it is best to be capable to create an occasion of this class and be capable to cross it into the GoogleMap composable. To work round this, the category was mirrored to a Maps Compose sort, MapUiSettings. The naming intently matches the present UiSettings class with the extra “Map” prefix to assist with discoverability of the API. MapUiSettings has the identical actual properties and default values as UiSettings, the distinction being that it may be created and handed into the GoogleMap composable versus acquiring and mutating it from one other management floor:
There are different properties of the map that may be modified at runtime (for instance, setBuildingsEnabled(boolean)). One consideration we had was to show these properties as particular person parameters on the GoogleMap composable; nonetheless, that will considerably improve the variety of parameters since there are plenty of properties that may be toggled. As an alternative, we opted to create a separate class, MapProperties, which comprises these runtime-configured properties:
For objects that may be drawn on the map (markers, polylines, and many others.), the crucial View-based method is to name add* strategies like GoogleMap.addMarker(MarkerOptions) on the GoogleMap object. To transform this in Compose, the GoogleMap composable might settle for an inventory parameter for every drawing, nonetheless, this API may very well be tough to make use of for integrations that comprise plenty of drawn objects with complicated logic. As an alternative, we determined to show a Compose pleasant API — a generic content material lambda whereby drawings could be invoked as separate composables.
Want to attract a marker, polyline, or different supported drawn object on the map? Name the Marker, Polyline, or one other decorator composable perform within the content material lambda of the GoogleMap composable like so:
Lesson #2: Benefit from Kotlin options
The Maps SDK was constructed at a time earlier than Kotlin was a first-class language for writing Android apps. That mentioned, the Maps SDK is basically in-built Java. Jetpack Compose alternatively, is fully written in Kotlin and closely leans on Kotlin idioms. For Maps Compose, we additionally determined to lean in on Kotlin language options like coroutines to show a Kotlin idiomatic API.
As an example, Compose makes use of Kotlin’s coroutine suspending capabilities for animation APIs. So, it made sense to supply an analogous API for the underlying callback-based APIs within the Maps SDK. For instance, animating the digital camera and ready for it to finish could be carried out inside a coroutine scope:
For an inventory of different Kotlin idioms extensively utilized in Compose, see Kotlin for Jetpack Compose.
Lesson #3: Preserve consistency with different Compose toolkit APIs
Sustaining consistency with different Compose toolkit APIs permits good developer ergonomics. Doing so permits capabilities to be simpler to make use of, and thus quicker to develop with, because it follows a well-known conference with different APIs. Whether or not you’re a library or app developer, this consistency is important to advertise ease-of-use. The Compose API pointers is a wonderful useful resource for studying conventions adopted by Compose APIs.
Listed below are a number of patterns outlined within the pointers that Maps Compose adopts:
There have been a few situations the place my preliminary designs differed from these pointers, and I discovered it very useful to confer with them to regulate the API selections to raised align with Compose finest practices.
Lesson #4: Plain courses are finest for binary compatibility
Kotlin information courses are an environment friendly technique to maintain information. They provide a handful of generated strategies that you just don’t have to jot down your self, saving you many traces of code per class. Nonetheless, should you’re writing a library, information courses have a hidden price as future modifications to the info class break binary compatibility. Including new properties will change the generated technique signature for copy(), and relying on the place the brand new property was added, it might additionally break destructuring capabilities thereby breaking shoppers. To mitigate this, Maps Compose makes use of plain courses for MapUiSetting and MapProperties. Hat tip to Jake Wharton for pointing this out in his Public API challenges in Kotlin weblog submit.
Lesson #5: Use Compose frequent sorts
To customise colours of a drawn object within the Maps SDK, you present it a colour integer. For instance, to customise a Circle’s fill colour you present it a colour integer when developing the CircleOptions object. The Maps Compose Circle alternatively, makes use of the Compose offered Shade class as an alternative.
One of many superior options of Compose is its built-in help for making use of materials theming to your app. So by utilizing the Compose offered Shade class, when the GoogleMap and its kids composables are used inside a MaterialTheme, the colours mechanically adapt to your theme’s colours when the system look modifications to both mild or darkish mode.
Lesson #6: Subcompositions are highly effective
Early within the growth course of, we recognized that including and eradicating map decorations utilizing facet impact APIs over time to match the app’s information mannequin was tedious and error inclined. The necessity to handle a tree of components is successfully the identical drawback as managing a composable UI tree, and so a greater resolution can be to make use of the identical underlying tooling for immediately updating the weather as state modifications over time. This method turned out to be much more easy and intuitive over utilizing uncomfortable side effects.
To realize this, we used the Applier class and the ComposeNode composable to help the child-based API (content material lambda) of including drawn objects (markers, polylines, polygons, and many others.) on the map. The ensuing implementation creates a brand new subcomposition that manages the map’s state as an alternative of Compose UI nodes.
Taking a marker for instance, with subcomposition we’re ready to make sure that the map’s state is up to date as recomposition happens. So for instance, if a Marker composable was beforehand within the composition and was later eliminated, we are able to faucet into the suitable node removing technique to make sure the underlying Marker Maps SDK object can be faraway from the map.
General, I used to be impressed at how the obtainable Compose interop APIs made supporting the Maps SDK in Compose doable. Whereas a local implementation of the Maps SDK is to-be desired, Maps Compose bridges the hole for a lot of Maps builders utilizing Compose.
Hopefully you discovered this submit insightful and discovered a factor or two about designing Compose APIs and making Compose work with present View code.
Should you’re new to Compose or Maps Compose, take a look at the pattern apps to be taught extra:
If there’s something you’d wish to see subsequent, let me know and go away a remark beneath!