Android Engineer’s perspective
Flutter is a new technology that is clearly gaining more and more popularity among mobile developers. It also caught the attention of mobile engineers in our company.
At Tooploox we enjoy exploring new technologies and we can even try them out in the experimental initiative of the company called Tooploox Labs. It was in the Labs where my journey with Flutter began.
I’ve been working on our internal application called Offhub, which is used mainly for tracking employees’ time off. It also allows you to add medical leaves, manage your remote work, check each employee’s allocation to projects, their positions, skills and more. The web application already exists, so my job was to create the mobile version.
Before we get into the details, let’s take a look at what Flutter is and how it can be beneficial.
Flutter is an open source mobile app SDK made by Google. It’s used for creating native apps for both Android and iOS. The framework uses Dart as its programming language. Both Flutter and Dart are free and open-source.
The advantages of using Flutter
Flutter comes with some remarkable features, which are beneficial for companies as well as for mobile engineers.
Both developers and business owners will be happy with the fact that Flutter may highly increase productivity. We create our app for Android and iOS simultaneously. Needless to say, we need only one team of developers for the app maintenance.
Besides, Flutter widgets (application building blocks) are compatible with both platforms. This means the application can maintain exactly the same looks for Android and iOS and we can stick to only one set of designs.
Developer’s Point Of View
From the engineer’s perspective, Flutter has even more interesting features. The framework is full of predefined, ready-to-use Material Components Widgets, which can make the development easier and faster.
What’s also worth mentioning is Flutter’s hot reload feature. Hot reload enables us to instantly see the changes we make in our layouts. We often used it during the development, as it simply makes it faster. The feature was also irreplaceable when consulting any visual modifications made on the spot with our designers.
In addition, you can use the platform for further development of existing Android or iOS apps, written in Java, Kotlin, Swift, or C++. The existing part of your application will integrate well with Flutter. By the way, If you work in Android Studio or InteliJ, you can stick to those environments. Flutter can be easily installed and run in both of them.
However, if the goal is to use some platform specific functions, it’s also possible by using a platform specific language. This way you have the whole range of existing native libraries to choose from.
What’s also extraordinary about Flutter are the animations. Not only are they optimized to provide 60fps (frames per second) performance but are also easy to create. Just take a look at a commonly used hero animation in Flutter.
The statistics also seem to prove Flutter’s potential. According to Flutter User Survey, the vast majority (92%) of Flutter users are very satisfied or quite satisfied with the technology.
It is not surprising that more and more companies add Flutter to their stack and the list of Flutter apps is growing fast. This includes applications like Alibaba, Google AdWords, App Tree and more, some of which can be found in the Flutter showcase.
A quick dive into Flutter
Firstly, let’s take a look at Flutter’s most important concepts and features. “In Flutter everything is a widget”, that’s what you often hear from developers who already used the framework. Let’s explain this a little bit.
Widgets And Their Types
Widgets are application building blocks. They differ a lot from what we got used to in Android, since we don’t have separate layouts, fragments, controllers. Instead, we have the widget. It holds all the above within it.
A Widget Can Be One Of Two Types:
- Stateless, like: Text, RaisedButton, Icon Padding, AssetImage. The internal state of those widgets won’t change.
- Stateful, like: Animatable, Scrollable, Image, Form, Checkbox. Those widgets are dynamic and their state may change. When it happens, setState() gets called and the widget is rebuilt.
When It Comes To Layouts, We Can Divide Them Into:
- Widgets that hold only a single child, e.g. Container, SizedBox, Expanded, Padding
- Widgets that can have multiple children, like: Row, Column or Stack
There are also custom widgets which can be of all the mentioned types. These custom building blocks are created by extending Stateless or Stateful widget class.
Flutter provides us with some useful tools, like:
- Hot reload: it reloads an app in an instant. This feature comes in handy when modifying layouts. Make some changes to a view, click the thunder icon and the new version of your view is visible in a blink of an eye. An important thing to keep in mind, though, is that Flutter’s hot reload is not supported in all the cases.
- Dart analysis: it’s a very handy tool for finding potential errors and warnings in the Dart code and we used it all a lot during the development.
- Automatic code formatting in Android Studio (or InteliJ) is one of those features you use all the time. To trigger the formatting, just right-click in the code or on a package and select “Reformat Code with dartfmt”.
- Flutter widget inspector: it is used for finding a selected widget in a widget tree and deeper in the code. We haven’t used it that much, but it may be practical, especially for larger apps.
Dart is an object-oriented programming language of general purpose developed by Google. It is used in mobile application development, web development as well as on the server side. From the official website:
“Developers at Google and elsewhere use Dart to create high-quality, mission-critical apps for iOS, Android, and the web. With features aimed at client-side development, Dart is a great fit for both mobile and web apps.”
For sure, it is a great fit for mobile apps when compared to Java. On the other hand, the comparison with Kotlin doesn’t seem that optimistic for now, to put it mildly. I won’t get into details, but instead I encourage you to read Kotlin Developer’s thoughts on Dart.
The app core functionalities include:
- Displaying the list of users with some basic information, current status and a leave ending date, if the employee is away.
- Displaying each employee’s basic info, their leave list and allocations in the detail view
- Changing the “remotely now” status from the profile view
- Adding a new time off
This is how the app looks:
Offhub Flutter app
On a daily basis I use Android Studio, so I decided to implement the app in this environment. Configuring Flutter in Android Studio and integrating Dart to the environment is painless and done within a few steps. For a smooth start, we get a simple counter application.
The architecture is influenced by the Clean Architecture principles. It is split into three independent layers:
- app: holds the application views
- data: the API layer
- domain: holds the business logic
This structure is beneficial, because the views can be modified without impacting the rest of the application. The domain is also separate and does not depend neither on the API, nor on the UI. In addition, the business logic is unconscious of any external interfaces used in the app. As a result, we have an easily testable application.
Flutter is often connected with Redux and there are many resources on the web about the use of Redux in Flutter. So, what is Redux?
Redux provides help with managing your application state. It’s mostly applied in the apps, that use reactive frameworks like React Native or Flutter. Although Redux may seem a natural choice for a Flutter app, we decided not to go for it.
Why Not Redux?
First, let’s consider when it makes sense to use Redux.
The Redux website points out these three conditions that ought to be met to justify its use:
1. You have reasonable amount of data changing over time
2. You need a single source of truth for your state
3. You find that keeping all your state in a top-level component is no longer sufficient
In our case, we didn’t feel like meeting any the above criteria. So, although Redux seems very popular among Flutter developers, for Offhub it would probably be on the over-optimised side. On the other hand, the MVVM pattern seemed just well-fitted for the limited needs.
In Flutter, it’s fairly easy to get into a situation where we have over-complicated views that contain both business and view-related logic. In order to avoid this, we decided to take advantage of the MVVM (Model – View -ViewModel) architectural pattern.
In MVVM, the views are only responsible for showing the data and informing View Model about any user interactions with it. In practice, it comes down to view models managing application states and views acting upon those states.
Apart from that, a view model is responsible for reacting to the user’s interactions with the view and producing data that the view can subscribe to.
What we can tell is that this approach provides a pretty nice ratio of value to complexity (or development time).
For more details, check how to implement MVVM in Flutter.
Challenges Faced During The Development
At the very beginning, I had a hard time getting used to Dart. I came from Kotlin and the syntax seemed a little bit bizarre. Some our team members also shared this opinion.
In Dart, the code is much wider, compared to Kotlin, owing to the dartfm formatting. We have dangling commas that are used for formatting and semicolons (that everybody complains about).
Building application the Flutter way. by using widgets, was also hard to get used to. It differs significantly from the way of developing Android applications. It’s mainly due to “everything is a widget” approach and also because of the widget which contains all the data that I got used to see as separate. The selection of the right widget also takes some time, as there are a lot of them. So, at first I got stuck in the docks browsing for the best widget to get the job done.
Surprisingly, customisation of some Flutter built-in widgets, in order to match the designs, was somewhat troublesome, but maybe it was due to my lack of experience in this technology. After a while, when I got to know the common widgets, the development became much faster.
When to consider using Flutter
It’s worth considering Flutter when you need an application that works on both Android and iOS platforms. From my experience, it’s good to have some fair amount of time for the iOS configuration and release or even better ask the iOS developer to help you get the job done in Xcode.
If your app has custom UI or uses material-design, that’s another point for Flutter. There are many build-in Material Component Widgets, which are ready for use out of the box. This can save you some time and hassle after you get to know them well.
Prototyping may be another good reason to choose this platform. Thanks to the variety of built-in widgets, you can quickly develop a simplified app version, suitable for both platforms.
When Flutter may not be the best choice
There might be a better choice, if an app uses many device-oriented functions, e.g. cameras.
On the other hand, if you have a limited number of such functions in your app, you may still consider using Flutter. It is possible to write the feature in a platform specific language (Java, Kotlin Swift, C++), taking advantage of all the existing libraries and incorporate it into your Flutter app.
If you come from Kotlin, it’s worth mentioning that you may be a little bit disappointed with Dart. Is it enough to stop using Flutter – that’s the question you need to answer.
Flutter is a very interesting technology with high potential. It has some important advantages, the most remarkable being the ability to create native applications for both Android and iOS at the same time. The built-in widgets can save you a considerable amount of time after you get to know them well.
There is room for improvement, however, especially when it comes to Dart.
Still, with strong community and support that it has we can only expect it to grow.
Warm thanks to:
- Tooploox Android team for strong support throughout the whole journey.
- Tooploox iOS team for helping with the iOS-side configurations.
Thanks a lot!