- Why Flutter Will Change Mobile Development for the Best
- By Aaron Oertel
- The Nuggets translation Project
- Permanent link to this article: github.com/xitu/gold-m…
- Translator: ALVINYEH
- Proofreader: Starrier, Jellycsc
Why does Flutter best change mobile development
If you’re an Android developer, you’ve probably heard of Flutter. This is a relatively new, simple framework for making cross-platform native applications. It’s not the first product of its kind, but it’s being used by Google, which gives it some credibility. Although I had reservations about the framework when I first heard about it, I decided on a whim to give it a shot — and it dramatically changed my view of mobile development in a week. Here’s what I learned.
“Long-beaked Hummingbirds Fly through the Air,” by Randall Ruiz of Unsplash.
Before we begin, let me add a brief disclaimer. The applications I’ve written and referenced in this article are relatively basic and do not contain a lot of business logic. This is nothing special, but I would like to share my knowledge and experience from porting native Android apps to Flutter. This is my best example. The application does not make any effort to optimize the architecture, it is purely for the experience of developing and using the framework itself.
Exactly a year ago, I released my first Android app on the Play Store. The application (Github) is very basic in terms of architecture and coding specifications. This is my first big open source project, which shows that I’ve been working on Android apps for a long time. I work for an agency and spend time working on projects with different technologies and architectures including Kotlin, Dagger, RxJava, MVP, MVVM, VIPER, etc., which have greatly improved my Android development skills.
That being said, I’ve been very disappointed with the Android framework over the past few months, especially with its poor compatibility and often finding it counterintuitive when developing apps. Not to mention the build time… (I recommend you read this article for a more in-depth analysis of the details.) While Kotlin and tools like Databinding can make a difference, the whole situation feels like putting a Band-aid on a wound that’s too big to heal. Let’s start with Flutter.
I started using Flutter a few weeks ago when it went into beta. I took a look at the official documentation (great, by the way) and started browsing the code LABS and guides. I began to understand the basic idea behind Flutter and decided to give it a try myself to see if I could put it into practice. I started thinking about what kind of project I should do first, and I decided to rewrite my first Android project. This seemed like an appropriate choice, because it allowed me to compare the same “first effort” in two corresponding frameworks without paying too much attention to application architecture, etc. It learns about the SDK purely by developing a defined set of features.
I started by creating network requests, parsing JSON data, and getting used to Dart’s single-threaded concurrency model (which alone could be the subject of another whole article). I started running some movie data in my app and then started creating layouts for lists and list items. Creating layouts in Flutter is as simple as extending stateless or stateful widget classes plus some method overrides. I will compare the differences between Flutter and Andriod in implementing these functions. Let’s start with the steps to build this list in Android:
- Create a list item layout file in an XML file
- Create adapter to extend item-views and set data
- Create a list layout (in an Activity or Fragment)
- Call the inflate method in your Fragment or Activity to create the list layout
- Create adapter instances, layout-manager, and so on in your Fragment or Activity
- On the background thread, download the movie data from the network
- Go back to the main thread and set the item on the Adapter
- Now we need to worry about some details, such as saving and restoring list-state
- … The list goes on and on
Of course, it’s boring. If you think about the fact that developing these features is a fairly common task — seriously, it’s not some particularly rare use case that you’re unlikely to encounter — you might think: Is there really no better way to do it? A less error-prone approach might involve less template code and speed up development. This is when Flutter was born.
You can think of Flutter as the result of what people have learned over the years in mobile app development, state management, application architecture, and so on, which is why it is so similar to React. Once you start coding, Flutter will make sense. Let’s see how Flutter can be used to achieve the above example:
- Create a stateless control for movie Item (stateless, because we only have static properties) that takes a constructor argument like Movie (for example, the Dart class) and describes the layout in a declarative way, binding the values of movie (movie name, release date, and so on) to the control.
- Create a control for list as well. (For the purposes of this article, I’ll try to keep the examples simple. Obviously, we need to add error states and so on, which is just one thing in the development process.)
@override
Widget build(BuildContext context) {
return new FutureBuilder(
future: widget.provider.loadMedia(widget.category),
builder: (BuildContext context, AsyncSnapshot<List<MediaItem>> snapshot) {
return !snapshot.hasData
? new Container(
child: new CircularProgressIndicator(),
)
: new ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) =>
new MovieListItem(snapshot.data[index]),
);
}
);
}
Copy the code
Movie-list-screen layout section.
To solve this problem, let’s look at what’s going on here. Most importantly, we use FutureBuilder (part of the Flutter SDK), which requires us to specify a Future (API call in our example) and the Builder function. The Builder function gives us a BuildContext and the index to return the item. With this, we can retrieve a movie based on the list of Future and snapshot results, and create a Movielistitem-widget (created in Step 1) as an argument to the constructor.
Then, when the build method is called for the first time, we wait for the value of the Future. Once the value is there, the Builder is called again by the data (snapshot) and we can use it to build our UI interface.
These two classes, together with API calls, will have the following effect:
Completed movie list function.
Well, that’s easy. Almost too simple… Realizing how easy it was to create a list with Flutter piqued my curiosity and made me even more excited to continue developing with Flutter.
The next step is to figure out how to use a more complex layout. The movie details page of the native application has a fairly complex layout, including the constraint layout and an application bar. I think this is a feature that users have come to expect and appreciate. If Flutter really wants to stand a chance against Android, it needs to be able to offer a more complex layout like this. Let’s see what I created:
Movie details page.
The layout consists of a SliverAppBar that contains layered layouts, gradients, small bubbles, and text overlays for movie images. Being able to express the layout in a modular way makes it very simple to create this rather complex layout. This page is implemented as follows:
@override
Widget build(BuildContext context) {
return new Scaffold(
backgroundColor: primary,
body: new CustomScrollView(
slivers: <Widget>[
_buildAppBar(widget._mediaItem),
_buildContentSection(widget._mediaItem),
],
)
);
}
Copy the code
The main way to build detailed pages.
When building a layout, I find myself modularizing parts of the layout into variables, methods, or other widgets. For example, the text bubble at the top of the image is just another widget that takes text and a background color as parameters. Creating a custom view is as simple as this:
import 'package:flutter/material.dart';
class TextBubble extends StatelessWidget {
final String text;
final Color backgroundColor;
final Color textColor;
TextBubble(this.text,
{this.backgroundColor = const Color(0xFF424242),
this.textColor = Colors.white});
@override
Widget build(BuildContext context) {
returnnew Container( decoration: new BoxDecoration( color: backgroundColor, shape: BoxShape.rectangle, borderRadius: Circular (12.0)), child: new Padding(Padding: const EdgeInsets. Symmetric (vertical: 4.0, horizontal: 6.0), child: new Text(Text, style: new TextStyle(color: textColor, fontSize: 12.0),),); }}Copy the code
TextBubble widget class.
Imagine how hard it would be to build a custom view like this in Android. With Flutter, however, this is a matter of minutes. The ability to extract portions of the UI into separate units like widgets makes it easy to reuse those widgets across applications, even across different applications. You’ll notice that a lot of the layout was reused across different views of the app, and let me tell you: it was a piece of cake to implement, so I decided to expand the app to include TV shows. A few hours later, the job was done. The app is a mash-up of movies and TV shows, and doesn’t cause a lot of headaches in the process. I did this by building generic classes for loading and displaying data, which allowed me to reuse each layout for movies and shows. However, in order to accomplish the same thing on Android, I had to use different activities for movies and shows. You can imagine how quickly this can be maintained, but I don’t think Android is flexible enough to share these layouts in a cleaner, simpler way.
At the end of the Flutter experiment, I came to a very direct and more convincing conclusion:
I was able to write better, more maintainable code that ran on both iOS and Android in considerably less time and with less code.
One of the best part is don’t have to deal with things like fragments could and SupportCompatFragmentManagerCompat, and saved in the form of a tedious and error-prone and manual management status. It wasn’t as frustrating as Android development… No more waiting for a 30-second “instant reload” to change the font size of the TextView. No longer use XML for layout. No more findViewById (I know there are tools like Butterknife, Databinding, Kotlin-Extensions, but you get the idea). No more boilerplate code — just results.
Once the two applications were functionally more or less on the same page, I wondered if there was any difference in the number of lines of code. How does one repository compare to another? (Quick disclaimer: I haven’t integrated persistent storage into the Flutter app yet, and the original app’s code base is pretty messy). Let’s compare the code in Cloc. For simplicity, let’s take a look at Java and XML files on Android, and the number of Dart files on the Flutter app (excluding third-party libraries, which can greatly increase Android’s measurement).
Writing native Android apps in Java:
Meta-Data forThe native Android app http://cloc.sourceforge.net v 1.60 T = 0.42 s (431.4 files/s, 37607.1 lines/s) -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- Language files blank comment code -------------------------------------------------------------------------------- Java 83 2405 512 8599 XML 96 478 28 3577 Bourne Again Shell 1 19 20 121 DOS Batch 1 24 2 64 IDL 1 2 0 15 -------------------------------------------------------------------------------- SUM: 182 2928 562 12376Copy the code
Flutter:
Meta-Date forThe Flutter app http://cloc.sourceforge.net v 1.60 T = 0.16 s (247.5 files/s, 14905.1 lines/s) -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- Language files blank comment code -------------------------------------------------------------------------------- Dart 31 263 39 1735 Bourne Again Shell 1 19 20 121 DOS Batch 1 24 2 64 XML 3 3 22 35 YAML 1 9 9 17 Objective C 2 4 1 16 C/C++ Header 1 2 0 4 -------------------------------------------------------------------------------- SUM: 40, 324, 93, 1992 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --Copy the code
To solve this problem let’s compare the number of files that Flutter: Android: 179 (.java and.xml) Flutter: 31 (.dart) Wow! There are also lines of code in the file: Android: 12176, Flutter: 1735
This is incredible! I thought that Flutter might have half the code of the native Android app, but 85% less code? This really took me by surprise. But it makes a lot of sense when you start to think about it: because all the layout, backgrounds, ICONS, and so on need to be specified in XML, you still need to link to the application using Java or Kotlin code, which of course is a lot of code. Flutter, on the other hand, can perform all of these operations simultaneously, binding these values to the UI. You can do all this without having to deal with the pitfalls of Android data binding, such as setting up listeners or handling the generated binding code. I began to realize how cumbersome it was to develop these basic features on Android. Why write the same code for Fragment/Activity parameters, Adapter, state management, and recovery?
With Flutter, you focus only on your product and how it is developed. The SDK feels more like a help than a burden.
Of course, this is just the beginning of Flutter, as it is still in beta and has not yet reached the level of maturity that Android has. However, Android seems to have reached its limits by comparison, and we may soon be writing our Android applications with Flutter. There are still some issues to be resolved, but overall, Flutter has a bright future. We already have great plug-ins for Android Studio, VS Code and IntelliJ, profilers and view-checking tools, and more are coming. All of this leads me to believe that Flutter is not only another cross-platform framework, but also the beginning of something much bigger — the beginning of a new era of application development.
And Flutter can go far beyond Android and iOS. If you’ve been following the grapevine, you’ve probably heard that Google is working on a new operating system called Fuchsia. It turns out that Fuchsia’s UI interface is built with Flutter.
Of course, you may be asking yourself: Do I now have to learn a whole new framework? We’re just starting to learn about Kotlin and using some of the architectural components, and now everything is fine. Why do we need to understand Flutter? But let me tell you something: After using Flutter, you will begin to understand the problems of Android development, and it is clear that Flutter is designed to be more suitable for modern, responsive applications.
When I first used Android’s Databinding framework, Databinding, I thought it was revolutionary, but it also felt like an incomplete product. When working with Boolean expressions, listeners and more complex layouts were a tedious step for Databinding, which made me realize that Android was not designed for such a tool. Now if you look at Flutter, it uses the same idea as Databinding. It binds your view or control to a variable without having to manually implement it in Java or Kotlin, and it doesn’t need to connect XML to Java by generating binding files. This allows you to compress at least one previous XML and Java file into a reusable Dart class.
I also think that layout files on Android don’t do anything by themselves. They must first call the inflate method, and only then can we set the value. It also introduces the problem of state management and raises the question: what do we do when the base value changes? Manually grab a reference to the corresponding view and reassign? This solution is very error-prone, and I don’t think it’s a good way to manage views like this. Instead, we should use state to describe our layout and let the framework take over by rerendering the view whose value has changed every time the state changes. This way, our application state is not out of sync with what the view displays. That’s what Flutter does!
There may be more: Have you ever asked yourself why creating a toolbar menu on Android is so complicated? Why do we use XML to describe menu items, and we can’t bind any business logic to it here (that’s the whole point of menus), we can only write it in the Activity/Fragment callback and then bind the click listener in another callback. Why can’t we do these things all at once like Flutter?
class ToolbarDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
actions: <Widget>[
new IconButton(
icon: new Icon(Icons.star),
onPressed: _handleClickFavorite
),
new IconButton(
icon: new Icon(Icons.add),
onPressed: _handleClickAdd
)
],
),
body: new MovieDetailScreen(),
);
}
_handleClickFavorite() {}
_handleClickAdd() {}}Copy the code
Add menu items to the Toolbar with Flutter.
As you can see in the code snippet, we add menu items as actions to the AppBar. That’s all you need to do — no more importing ICONS into XML files, no more overwriting callbacks. This is as simple as adding some controls to the control tree.
I could go on and on, but here’s the thing: Think about all the things you don’t like about Android development, and then redesign the framework while figuring out how to fix them. This is a daunting task, but doing so can help you understand why Flutter exists and, more importantly, why it can stay. To be fair, there are a lot of apps (from now on) I’ll still be writing with native Android along with Kotilin, and native Android may have its drawbacks, but it also has its benefits. But at the end of the day, I think that with Flutter, it will become increasingly difficult to develop an application using native Android.
By the way, both apps are open source and both are on the PlayStore. You can find Flutter here: native Android: Github and PlayStore: Github and PlayStore
The Nuggets Translation Project is a community that translates quality Internet technical articles from English sharing articles on nuggets. The content covers Android, iOS, front-end, back-end, blockchain, products, design, artificial intelligence and other fields. If you want to see more high-quality translation, please continue to pay attention to the Translation plan of Digging Gold, the official Weibo, Zhihu column.