Takeaways comparing Flutter to Jetpack Compose
DISCLAIMER: This article was written in January 2020, when Jetpack Compose was still in a very early state. Much has changed since then and this article might not represent the differences any more. Be cautious!
Last week I attended the Flutter Europe conference. I went in with just the barest knowledge of Flutter, so I learned a lot. During this week, I also ported the Jetnews sample app to Flutter to get a hang of the platform. In this blog I’ll summarise my experiences on this journey.
First of all, and most importantly, comparing Flutter and Jetpack Compose is like comparing apples and oranges. And then some. Flutter is a full-fledged, production-ready platform, written in Dart, meant for cross-platform development. Jetpack Compose is a new UI toolkit that Google is working on, written in Kotlin, meant only for native Android development, and far from being usable in production apps.
This post is not about choosing one over the other, because the use cases for Flutter are completely different from the ones for Jetpack Compose. Even better, there is no real use case for using Jetpack Compose yet, since it’s still under heavy development and only usable through a developer preview.
However… Both are interesting to look at as an Android developer. You might want to do a career switch to Flutter somewhere in the future. Or you might want to stick with native Android development and implement Jetpack Compose when it gets to a stable release.
Since both techniques work with the concept of “declarative UI”, they are quite comparable. Especially the way they use code to describe the UI is alike. Therefore, learning about one can help you learn about the other, and knowing one will help you quickly getting up to speed with the other. If you haven’t heard about declarative UI, the Flutter documentation page describes it really well, which is useful for the rest of this article.
So, let’s dive in and look at some of the differences!
Widgets and Composables
Let’s start with a basic “View” (taken from the Jetnews app at Github), which should look like this:
I’m calling it a View just to confuse you. This thing you would call a Widget in Flutter, and a Composable in Jetpack Compose. For now, I’ll refer to it as a composable widget, so I don’t have to pick one terminology over another.
Let’s take a look at the general implementation of this composable widget in the two frameworks (don’t worry, you don’t have to read the whole thing):
The first thing that’s immediately obvious is that Flutter takes a lot more lines to accomplish the same thing. This was also my general experience when I was trying it out. Because everything is a Widget, you’re constantly adding layers of nesting. Jetpack Compose is taking shortcuts here and there, using parameters or extension methods instead. For me as a beginner this was a big deal, but I can imagine you get used to Flutter’s nesting and there will be tooling to hide some less important layers. For example, the latest release of dart adds extension methods to the language, so Flutter can start using those for simplifying some cumbersome Widgets like Padding.
So let’s zoom in a bit on a specific part of the composable widget:
Here we see a lot less stuff in the Jetpack Compose variant. Most of this is due to the Kotlin DSL that was made for Jetpack Compose. If you don’t know what a Kotlin DSL is, you can read a bit more about it in the documentation. In summary, it helps us write declarative code in a nice format.
Another thing we see in the Jetpack Compose sample is the use of the withOpacity
extension function. This may look great, but when we look at the documentation of this method, we see another indication that this toolkit is still in its early stages. It reads:
TEMPORARY solution to apply an opacity for the [TextStyle] even if it has no color provided. We wanted to have this right now to improve our tutorial for ADS. But the problem is actually way wider and we would need to rethink how we apply modifications like this to our styles and do we need similar methods for other params we have in TextStyle. We will continue investigation as part of b/141362712
So to summarise, both UI descriptions look quite similar. Widget or composable means pretty much the same thing, and besides some boilerplate differences, they look very much alike.
Hot Reload and @Preview
If you’re an Android developer, you probably have a healthy distaste for anything that promises to change your app’s code while it’s running on the device. Previous versions of Android Studio contained a feature called “Instant Run” which promised to do just that. However, this often did not work or led to subtle bugs, and you always ended up re-building the whole app anyway.
So naturally I was a bit skeptical when Flutter mentioned “Hot Reloading”. And to be fair, in my first hours with Flutter I did re-build the application a lot of times because I didn’t believe it was Hot Reloading as fast as it did. But it was. This is a game-changer! Whatever you change in your UI, the app just continues running, the state is preserved, and the changes are immediately reflected in the app. I can’t stress enough how amazing this is for a mobile developer, and how much I want this!
On the other hand, Jetpack Compose also has quite an amazing feature so you can preview your Composables. You can add a Composable which you annotate with @Preview, and it will be rendered in the Design tab of your IDE. I see a lot of potential for this feature using it for Design System documentation. For example, imagine you want to check how a Composable will look in light mode vs dark mode. Or you want to see how it behaves with different types of inputs. You could add multiple @Preview methods and they will display like this:
Both Hot Reloading and @Preview are amazing in my opinion. In my ideal world, I’d like to have a mix of both. It seems Flutter is currently working on a feature called HotUI (video here) which could get close to @Preview in functionality. Let’s hope that Jetpack Compose can also pick up hot reloading!
Other random thoughts
In this blog post I compare Flutter and Jetpack Compose, but they seem to be two samples of a much broader movement in tech towards declarative UIs. Apple released SwiftUI, which is similar to Jetpack Compose in its features. On web, the trend has been going on for longer, with React gaining a lot of traction. It’s interesting to watch this shift happening, and I’m intrigued to see where this will end.
For the sample app I was writing with Flutter, I needed some simple model classes. I’m used to working with data classes and sealed classes in Kotlin, and was expecting to be able to find the same in the Dart language, used for Flutter. Boy, was I wrong. There is no easy way to write an immutable data structure that automatically deals with stuff like hashCode
and equals
. There is a Flutter library called build_value
that helps (see explanation) but that requires code generation. Maybe Kotlin developers are just spoiled 😬
At the conference I noticed that there’s a lot of discussion going on in the Flutter world around state management and architectural patterns. It seems the community is choosing a wide range of possible patterns, ranging from using the basic setState
method provided by Flutter, all the way to using the very opinionated redux
architecture and corresponding package, with stuff like provider
, bloc
and mobX
in the middle. I’m curious about the patterns that will emerge and stabilize.
In Jetpack Compose, there is some talk about state management. You can pass an @Model instance to your subtree of Composables to pass data, or use something called an Ambient to create some data that should be accessible from other places. However, documentation is still quite sparse on this, and I haven’t had the time to really investigate it. In a next blog I’ll dive deeper into state management with Compose, describing the current landscape and trying to look into what the future will bring. Follow me on Twitter to get a notification when this blog is finished!
Comparing Flutter and Jetpack Compose was very interesting, being new to both and being new to declarative programming. Returning from the conference I’m left with a positive feeling. There is a very nice Flutter community and I think that Flutter makes a lot of sense as the tool of choice for many companies. However, I’m sticking around for Jetpack Compose, which also promises great things but will need some more love before it will blossom.
You can find the source code for the Flutter implementation of Jetnews here. Thanks for reading, feel free to reach out to me through Twitter or leave a comment!
Thanks to @Sebastian Lobato Genco for fact-checking my Flutter statements, Zsolt Kocsi for fact-checking the Compose statements, and Jovche Mitrejchevski for fact-checking my grammar. And a big thank you to Wim Verhoef for all the brainstorming and discussions during our trip to Poland!