How Flutter works under the hood and why it is game-changing

Flutter is Google’s latest mobile app SDK to develop beautiful, pixel-perfect, buttery smooth native apps for Android and iOS in record time. It integrates with your existing Android- and iOS-code and is used by many organizations – such as Alibaba – around the world.

This short introduction is packed with a lot of information and promises. Let’s have a look under the hood of Flutter and see how it works and why it is a game-changing SDK for app development.

Flutter System Architecture

Stateless or stateful Widgets are the building blocks of any Flutter app and can be themed to look like native Android (Material) or iOS (Cupertino) UI components. Widgets are rendered onto a Skia canvas with support for advanced animations and gesture recognition.

Source: Based on Flutter System Architecture

Flutter’s engine hosts the core technologies Skia – a 2D graphics rendering library – and the Dart language VM in a platform-specific shell. Any shell implements the respective platform APIs and handles the system’s application lifecycle events.

Using the Dart language allows Flutter to compile the source code ahead-of-time to native code. The engine’s C/C++code is compiled with Android’s NDK or iOS’ LLVM. Both pieces are wrapped in a “runner” Android and iOS project, resulting in an apk or ipa file respectively. On app launch, any rendering, input, or event is delegated to the compiled Flutter engine and app code. Having to package the engine with the app’s apk/ipa file currently leads to an increased app size of 4MB.

Fast startup and execution of an app are the benefits of compilation to native code. The UI is refreshed at 60fps – mostly using the GPU –  and every pixel on the screen is owned by the Skia canvas which leads to a smooth, highly customizable UI.

For more detailed information about the system architecture and how it differentiates itself from e.g. platform SDKs, web views, and reactive views check out the following articles.

Why Flutter uses Dart

The Dart language is crucial for Flutter’s success. Wm Leler put together a great post about why Flutter uses Dart. I highly encourage you to check it out as I will only provide a brief rundown in the following.

  • Dart is ahead-of-time (AOT) compiled into fast native X86 or ARM code for Android and iOS devices.
  • Additionally, Dart can be just-in-time (JIT) compiled. This comes in handy during the development phase. It enables Flutter’s sub-second hot reload – which is significantly faster than Android’s Instant Run.
  • Flutter uses Dart 2 – a garbage-collected, object-oriented language with a sound type system and type inferencing.
  • Dart is single-threaded and does not allow preemptive scheduling nor shared memory. Hence, garbage collection is extremely fast and memory locks are not required. Threads explicitly yield using e.g. async/await. For Android and iOS, “a dedicated thread is created for the UI, GPU and IO task runners per engine instance. All engine instances share the same platform thread and task runner.” (see here)
  • Dart has great tooling and IDE support in IntelliJ, Android Studio, and Visual Studio Code. IMHO it exceeds XCode’s support for Swift and Objective C by far.
  • Dart has a fast-growing community and an extensive set of libraries and packages that can be used in Flutter apps. Find them on Dart’s package manager.
  • Dart is very easy to learn for any developer – no matter if her background is C, Java, Kotlin, Swift, JS, Ruby, etc. Some organizations claim that with Flutter it is much easier to hire skilled developers because their background does not matter as much. In contrast, I hear a lot of Android and iOS developers struggling with e.g. React Native at first – as they feel it’s more tailored towards web developers.

Why Flutter is game-changing

The above-mentioned benefits of Flutter should be reason enough to give it a try – but you might wonder if it is actually production ready.

In December 2018, Flutter 1.0 was announced – after a really long and stable beta phase. At the time, 3000+ Flutter apps have been published, including Alibaba’s 50+ million users Xianyu app.

It is to be noted that Alibaba did not rewrite the Xianyu app from scratch, but integrated Flutter with their existing code base for Android and iOS respectively. They implemented highly frequented app features with Flutter for both platforms, leaving the rest of the app unchanged. I cannot stress enough the importance of this feature as a rewrite of an existing app is – in most cases – not feasible for organizations. Tomek at Groupon gives you a rundown of how to integrate Flutter into an existing app in his three-part blog series.

When it comes to building successful apps for millions of users, testing support and continuous integration (CI) and – delivery (CD) tooling are must-haves for frameworks like Flutter.

Flutter/Dart has fantastic testing support for Unit-, Widget-, and Integration tests. Particularly unit tests have significantly faster compile and execution time than respective tests on the Android and iOS platform. Due to code sharing, there is no more excuse, to not write test cases and high test coverage can be maintained for all platforms. Additionally, QA testing will have high confidence that Android & iOS code behaves in the same way and more scenarios can be tested in less time.

Although several CI/CD services support Flutter, Codemagic was specifically created for Flutter projects. Their CI/CD service is set up in very few minutes and can be easily customized. Moreover, the service is still free of charge – which might change in the future.

The cherry on top is the project “Hummingbird”. It was presented during the Flutter Live event on December 4th, 2018. In the future, Flutter will have official support for web development.


What are your thoughts on Flutter and what’s your biggest takeaway of this post?
Please provide feedback and drop us an email at flutter@elevateapps.de.

Set up your Android project for success

Having developed Android apps for startups as well as Fortune 500 companies for many years, I strongly believe that every successful Android app should have the following high-level design goals:

  • Pleasant user experience with a modern, fluent, and responsive UI
  • Offline support for spotty networks in e.g. subways
  • Maintainable, clean code base with high test coverage
  • Ability to A/B test the UI for rapid prototyping
  • Ability to release the app continuously to different user groups
  • Push-Notification- and App-Deep-Link-support to re-engage users

We rarely get the chance to start an app from scratch but don’t let this be an excuse to stick with outdated libraries, frameworks, practices, and with untested code. Instead, consider to apply my recommendations to your current project when e.g. implementing new features or new sections of your app. Thereby, you can keep your legacy code unchanged while slowly but surely improving your overall app quality.

In the following, I outline the Android project set up I aim for today – in February 2019. 

I start out with (1) some Android project basics, followed by (2) infrastructure recommendations that go beyond just writing maintainable source code. Then, (3) I outline some app architecture decisions that worked well for me in past projects and enabled (4) automated testing. To achieve all this more easily there are (5) some handy libraries and tools. I finish with (6) some additional tips. 

1. Basic setup

  • Use the latest Gradle build tool and its dependency management
  • Setup build flavors for e.g. development and production environments
  • The minimum API level is likely defined by the customer but should be no smaller than Android 5 (Level 21)
    • Use the Android Support Library AndroidX to bridge the gaps between API levels – make sure to adapt to AndroidX and not use the deprecated, version specific libraries.
  • Prefer Kotlin over Java
  • Use Lint tools to flag potential programming errors, bugs, code style, etc.

2. Infrastructure

  • Use Git version control with master, develop, and feature branches. Tag releases and enforce merge between branches only via pull request (PR)
  • Use Continuous Integration (CI) – e.g. setup Jenkins to build and run (unit) tests on every commit. At least the nightly build must run integration tests, too.
    • Optionally, SonarQube could be setup to find code smells and enforce test coverage in form of a quality gate for every release.
  • Require PR review by at least one other developer and allow to merge branches only if the CI build of that branch is passing and marked “green”
  • Setup AppCenter (formerly HockeyApp) to be able to release app versions and flavors to custom distribution groups (e.g. developers, testers, clients, beta users, …)
    • AppCenter also comes with crash reports and analytics, which will help with fixing bugs reported by users

3. Architecture

  • Use the Model-View-ViewModel (MVVM) Architecture Pattern as it nicely separates concerns and enables unit testing of the business logic of the app
    • The Context or other Android resources are never to be used in models nor in view models to enforce their 100% unit testability
    • Introduce “Services” that provide functionality to ViewModels like receiving and persisting data etc.
    • Introduce Navigator(s) to centralize navigation between views using intents (don’t pass massive data as Parcelable but rather use ids to locally stored information)
    • Alternatively, the Model-View-Intent (MVI) pattern could be used as it nicely enforces immutable data/objects with a uni-directional data flow by design
  • “Package by feature” enforces separation of concerns and enables potential use of Android Instant App
    • Introduce a shared module for data models and common functionalities (e.g. date parsing)
  • Respect the Android life cycle at all times and use the lifecycle-aware components of Android Jetpack.
  • Create custom views to encapsulate common views – e.g. a customer specific date picker
  • Use dependency injection and generate the dependency graph automatically
    • This enables better testability as mock objects can be used
  • Use RxJava
    • As Android Apps are highly driven by asynchronous events and an app can be interrupted by the system at any time, RxJava has proven to be a key asset (more information below)
  • Use Androids’ shared preferences, file storage, and sqlite database to persist data locally
  • Use Android resource files to define themes, dimensions, images, strings, etc. and use respective subfolders for localization purposes and build flavor differences

4. Testing

  • Use Junit as much a possible – it is fast and unit testable code is a good indicator of well separation of concerns within the app
    • Use AssertJ for easier assertions 
    • Use Mockito to create mock objects of dependencies
    • Use the Arrange, Act, Assert structure within tests
  • Use Espresso for UI and integration testing 
    • Add at least one test that checks if the app main screen is shown after app launch
  • Monkey runner can be used to stress-test the app

5. Libraries / External tools

  • For dependency injection I recommend Koin for pure Kotlin projects, Dagger2 alternatively
    • Define at least a global app scope and an activity specific scope – add more specific scopes if needed
  • Room  – Android Jetpack’s persistence library – is the preferred way to harness the full power of SQLite
  • The Gson library is suited perfectly for JSON conversion.
  • Retrofit to perform REST (backend) calls – it uses Okhttp under the hood
    • Set up Okhttp to cache backend responses and downloaded images
  • Glide image library
    • Use cache and image transformations when displaying images for UI performance reasons and do not waste the user’s mobile data
  • RxJava 2 
    • Data flow can be modelled very nicely and asynchronous by design – events / data can be chained, filtered, composed, etc., threading can be explicitly defined, and observers can subscribe to events of interest
    • Introduce some RxBinderUtil that keeps track of subscriptions and is life cycle aware so it can dismiss active subscriptions in case of respective Android life cycle events
  • I advice to not use data binding as the benefits don’t justify increased build time and other drawbacks. With the introduction of Kotlin views can access ui elements by their id without using findViewById.

6. Miscellaneous

  • UI performance
    • Use RecyclerView for any sort of lists
    • Avoid deep nesting in layout files and use the Constraint Layout instead
  • Analytics 
    • It is already part of AppCenter but it might be useful to introduce e.g. Google Analytics for re-marketing via Google Ad Words. Please keep GDPR restrictions in mind. The user needs to explicitly consent to tracking of this kind. This also applies to the usage of Facebook SDK integrations for re-marketing or Single sign-on reasons.
  • For push notifications, I recommend Firebase messaging (also available for iOS)
  • Authentication 
    • Make use of Retrofit’s authentication interceptors to handle e.g. OAuth authentication
    • For a pleasant user-experience, allow the user to use Single sign-on via Google, Facebook, etc.
  • Permission management 
    • Since the user explicitly needs to grant permissions to the app to e.g. access his location, the core use cases should not require any of these platform features – it should be a nice-to-have for improved user experience

Aiming for this kind of project setup helped me deliver outstanding apps for clients and I’m more than happy to share my learnings with you. What’s the biggest take-away for you? Please provide feedback and drop me an email at android@elevateapps.de.

Must-follow ressources for every Android developer

Continuous learning to stay on top of modern Android development is crucial for every good developer. Here are my top picks of ressources I believe every Android developer should follow:

Mailing lists
Subscribe to the following three mailing lists to receive the latest and greatest news and learnings in Android and Kotlin development on a weekly basis:

1.) Android Weekly
2.) AndroidDev Digest
3.) Kotlin weekly

Podcasts
4.) Fragmented – each week, Donn Felker and Kaushik Gopal discuss interesting topics around Android development and often interview domain experts about their experiences.
5.) Android developers backstage – run by Tor Norbey and Chet Haase, every two weeks Google employees give insights in the Android platform and tools.
6.) Talking Kotlin – although not Android specific, Hadi Hariri covers everything with regards to the Kotlin programming language.

Blogs
7.) Medium – follow the Android hashtag
8.) Android Developers Blog – Google’s latest announcements

Android Camera Util Project

It seems to be the simplest thing in the world: taking a picture within your Android app using the default camera activity. However, there are many pitfalls which are covered in several posts across the web, such as:

  • null intents being passed back,
  • the orientation of the picture not being correct, or
  • OutOfMemoryErrors.

To safe you some time, I released my soultion as an open source project on GitHub:

https://github.com/ralfgehrer/AndroidCameraUtil