Lessons Learned with Jetpack Compose

Joe Williams
Making Meetup
Published in
5 min readMay 12, 2023
Photo by Brett Jordan on Unsplash

At Meetup, we are all-in on declarative UI. Our Organizer app was built from the ground up with Jetpack Compose and SwiftUI. We like it so much we’ve been integrating it into our existing Meetup app whenever possible. That road has not always been a smooth one, though, and we’d like to share some of what we’ve learned on that journey.

Making the switch is worth it

No doubt, some developers are hesitant to pick up yet another newly emerging Android technology. I certainly was. It’s tempting to stay in the comfort of XML layouts and view binding. But wouldn’t it be nice to create a screen with just one file? Do you really want to keep filling in boilerplate code for RecyclerViews and Adapters? We found that once everyone is on the same page with Compose, UI development speeds up significantly. Reusing a UI component is now just a matter of writing the declaration for it. No more extending a view, dropping it into an XML file, and then hooking up the backing code.

Set up previews and use Live Edit

When switching from XML layouts to Compose, the first downside that may jump out at developers is one of previewing the UI. For standard XML, changes made are reflected immediately in the design view, while Compose requires the app to be built.

There are two things that can help alleviate this problem: Previews and the Live Edit feature. Declaring previews allows you to see how your composables will look in a running app. This is especially useful for commonly used elements. For instance, we have a MeetupButton that gets used across both of our apps, so having previews of each version of it helps us quickly identify which one to use when we’re building a screen.

Previews also make it easy to test layouts without repeatedly running your application and simulating states:

Alongside previews, Live Edit lets you make changes to your composables while the app is running and see those changes immediately. Simply deploy your app from Android Studio to a device or emulator and navigate to the screen with the composable you’re editing. Then, while it’s running, you can make changes to literals in that composable and see them updated in real-time.

Google wants this to be easy

The Compose libraries provide two main elements to make integration with traditional layouts easier: ComposeView and AndroidView. If you’ve looked into Compose at all, you probably already know about the ComposeView, which allows you to add Composables to traditional layouts. This means that integrating declarative UI can be done in small bites. You can convert one element at a time in a screen, or add new screen elements as composables, without completely rewriting a fragment or activity.

That other element, the AndroidView, does the reverse: allowing Android views to be added to composables. You may be wondering why that would be useful if you’re implementing Compose. The usecase is for anything you want to reuse that you don’t have time to convert, as well as third-party libraries you may be using that don’t provide composables.

For example, before a composable wrapper was added to the Google Maps SDK, we had to create our own, using AndroidView, in order to include maps in our Organizer app. That implementation looks like this:

Java will require some workarounds

The Meetup app has been around for a long time, and several of our screens still have their backing code written in Java, so it’s a bummer that Compose and Java don’t get along very well. One solution is to convert those files to Kotlin, and that’s something we try to do when we have the bandwidth.

When there just isn’t time to do that for a new feature, though, a workaround is needed. One of the easiest we’ve found is creating a Kotlin object with a method that accepts a ComposeView and loads the composable into it, like this:

That is then used in a Java file like this:

Add a safety net with Paparazzi

Although Compose makes it easy to reuse UI elements, it’s also easy to wind up with changes that populate to other screens. This isn’t a new problem for anyone who has been reusing layouts or leaning on styles, but the generic nature of some Composable elements you create may mean it’s a more common issue. That’s where Paparazzi can help.

Paparazzi is a tool that can render your UI as a screenshot, without a device or emulator. Adding this to your CI/CD process means you can automatically compare instances of the same screen from one commit to the next and be alerted when something changes unexpectedly.

We chose to add Paparazzi snapshot tests for our low-level UI components, such as buttons and other widgets, but also to full screens. That way we’ll be warned if a change to a reusable component in one area of our app inadvertently breaks the layout for a completely different feature.

Here’s an example of a snapshot test for the Member+ subscription screen, which will fail if any code change causes a significant difference in the snapshot compared to the golden value.

Conclusion

As with many new technologies, the best way to learn Compose is to jump right in. It makes UI development faster and easier, whether you’re starting a new project or expanding an existing app.

Google and Jetbrains have provided previewing and integration tools to make the process as smooth as possible, even if you have legacy Java code or layouts that can’t yet be updated. We’ve enjoyed learning so much while building with Compose, and we think you will, too.

--

--