Shooting yourself in the foot guide, or is it possible on Flutter?
When I started to write this article I didn’t know how to code Flutter apps. To start this story let me introduce myself. I’m Andrew, Android Developer, not good not bad, just the regular. Also what I want to say about myself, is that I don’t like any cross-platform solutions. I already tried PhoneGap, Xamarin and of course React Native. I don’t want to talk a lot about advantages and disadvantages of these technologies, I just want to say that I don’t like them. Starting from the idea or architecture finishing IDE or programming language which is used here. It’s totally my subjective and PERSONAL opinion.
This December I had a chance to visit Flutter Live conference in London, where Flutter was officially released. There was a great keynote, interesting announcements. Flutter team showed impressive things, and they convinced me to check it out. But I’m still feeling pessimistic, as I think that native development is more flexible and brings more consistency for developers.
So what is this article about? It’s about comparing of course. You can say that Flutter and Native Android development is not possible to compare, because this technologies are different, and I’m totally agree with that. I want to compare different thing. It would be not architecture, language, IDE e.t.c. I want to compare leg-shooting.
As every Android Developer on start of my career, I did ugly and non-acceptable things during the app development (maybe I’m still doing that). So for the unexperienced developer it’s really easy to shoot into the own leg, and deliver shit. So the thing that I want to check in this article, is how difficult it is to write bad app on Android and on Flutter? I’ll try to create ugliest app ever using both technologies. And now we can define bad practices at least for Android development, mostly UI:
- Overdrawing. 6 years ago nobody cared about this. When I started, I’ve set backgrounds for each layout, and of course performance decreased like crazy.
- Lots of nested LinearLayouts, which brings a mess measuring and drawing UI.
- Doing heavy operations inside onDraw function.
- Blocking Main thread. It includes such things as working with files, string formatting, working with database, e.t.c.
- Memory leaks, and objects allocations.
So for this article I’ve chosen two common use-cases which can happen with all beginners.
- Dealing with huge images.
- Overdrawing and badly composed layouts.
So first case which I want to implement will be a simple list of images. Each image will have high resolution. For Android sample as image downloader I’ll use lovely Picasso. So the usecase looks easy and straightforward.
So we have a list of images. Obviously I’m going to use RecyclerView
One more thing — I’ll add more urls to the list to make RecyclerView scrollable.
Everything looks correct, so I used tutorials from documentation and I’m using one of the most common libraries for image loading and caching. As a beginner I did everything correct. But let’s check the app.
So this result is also obvious, because I’m using high res images, which is not wise. 100% it brings performance problems, and every android developer knows that we should not use high resolution images as preview. So in the first usecase for the really simple app we already have a performace problem. So to understand what is going on, I have to learn more about profiling, and have to try to fix this.
And obviously here I can press
Wait and app works not so bad:
But still, there are some janky frames as you can see.
Basically I still can release this app easily, ANR is not a crash and from the first view glitchy frames are not so annoying. But number of ANRs will affect the order of my app in the apps list (see Android Vitals) and it wil be +1 to garbage apps on Google Play. Not so good, is it?
So now let’s try to shoot the leg in Flutter. The same usecase. So I’ve installed all plugins and Flutter, and it’s my first Flutter application.
Here is the code
and for the MyHomePageState
All this code took around 20 minutes
- Reading “Getting started” from flutter.io.
- Setup Flutter.
- Searching for any collection view in the documentation.
- Searching for “How to load image by url in flutter?”
- Some copypasting.
I’m sure that if I would take more time, code will be much nicer. But is it really necessary? Let’s check the app
To be honest it looks smooth, much better than Native Android app. Later I’ll try to understand how Flutter engine works, but for now I checked first usecase. Some copypasting and the wallpaper app is almost ready to be published on both stores. Impressive.
Second usecase which I want to check, about ugly layouts. Beginners usually like to use LinearLayouts to build some complex screens. It’s one of the most common mistakes of beginner Android developers. But is it really bad for performance? Let’s see.
So here is the screen, and how it behaves:
So we have here couple of nested LinearLayouts, and ScrollViews — vertical and horizontal. Here is the full layout code. By purpose I did one more common mistake — setting same backgrounds to most of layouts and of course using some alpha to reduce performance.
So result of enabling GPU overdraw is quite obvious.
As we can see GPU overdrawing is 4k, so layout is ugly enough. Even for such simple screen sometimes we can reach the green line in GPU rendering profiling:
Honestly it’s easy to fix just reducing overdraw, and it will work better, but nested LinearLayouts still brings some bad points to the performance. So basically goal is reached: I did a pure ugliness making common beginners mistakes.
So Flutter turn.
For the second Flutter app in my life this layouts looks a bit complicated. So time to check documentation on flutter.io. And there are 11 scrolling widgets. Wow. So for the vertical lists I’ve chosen ListView, because I’ve already tried it. And for horizontal lists I’ve taken SingleChildScrollView, which works similar to Android ScrollView. Later I realised that actually I can use one of those widgets for horizontal and vertical scrolls (so obvious). And this is my result:
In total it took 1 hour coding, reading documentation and checking some StackOverflow answers. I assume that my code is the ugliest that you can imagine. It took 352 lines, and have many copy-pasting code.
So what about performance?
To profile Flutter app I’ve used this article from flutter.io. So the performance overlay looks like this:
The top graph is a GPU thread and the bottom is UI thread. Both graphs are looking good, and they show that app is well-performed. At the same time from Flutter Performance Monitor in Android Studio during scrolling I’ve got this
which is slightly bellow than 60 fps. This one looks for me as Approximation error
So the question is how Flutter performs so good?
The answer is really simple. It performs better because it’s completely different. It doesn’t use JVM which means that we can use here hot reload feature. All views that you can see on the screen are looking native, but in the same time the aren’t native at all. Flutter uses completely different approach to draw UI — SKIA engine, which is written on C++, and gives great performance. Using such solutions sounds a bit scary, because it could seemed that final result will look different comparing to Native app. But in Flutter’s case it’s not true — all views, their behaviour and animations are looking really native. Basically I’m sure that it’s not possible to recognise which app is Flutter app, and which not. So basically Flutter has more similarities with mobile game than with native app. Actually SKIA is so powerful that you can develop games here.
After implementing these two use-cases I found some advantages and disadvantages of Flutter. All of them are really subjective and it’s just my personal opinion.
- Easy to start. All setup took 20 minutes. It’s really impressive.
- Android Studio support. I think that Android Studio is one the best IDEs ever made. For Flutter all useful features of Android Studio are available.
- UI kit is flexible, you can have Android UI on iOS device and the other way around. Or you can have different UI depending on platform
- Hot reload is really fast. So if you work on UI, you can see all your changes in the real app.
- Documentation is awesome. Good work by Flutter team. For implementing these use-cases I’ve used just flutter.io to get information.
- Dart as the main language. I understand why Flutter team has chosen Dart, and it’s totally fair and makes sense. But this point is just about the language. Kotlin gives me more fun. :)
- Profiling doesn't work for emulators. It’s my personal pain point, because I don’t have testing device.
- You don’t need to care about code quality so much. Writing spaghetti 🍝 code is allowed, as soon is it doesn’t break performance. For me this point is the most painful. Now whole work is already done by Flutter, you don’t need to know how engine works, you don’t care about 60 fps, and of course you don’t care about code quality. I think these things will bring a bunch of non supportable projects, obfuscated by developer :) And when you’ll try to ask some project owner, manager or CEO, to refactor this, I believe they will ask you: why we should break something which works perfect?
To summarise everything, I just want to say that Flutter is the best cross-platform solution I have ever tried. It’s perfectly fits for prototyping apps, and for young and ambitious startups. For existing projects I would still use Native development.