Flutter – The new kid on the block

In this post I will have a closer look at Google's new mobile framework Flutter and compare it to my previous experience with Xamarin forms. This is not a tutorial but more an overview to get you started

A typical day with Xamarin

As most of you know I really like Xamarin Forms. After a break of halve a year I got back to mobile. First thing was updating Visual Studio with Xamarin. When trying to build my App which built fine the last time I was working on it I got a whole bunch of errors. After 3 hours fiddling with the toolchain I was able to build again.
Pretty frustrated because I had hoped that things had improved with Xamarin in the meantime I read that Google just announced the official beta release of its new cross platform mobile framework Flutter. So I decided to have a closer look at it.

What is Flutter

Flutter is not only a framework, it's actually a whole tool chain for building native Apps for Android and iOS.

  • Flutter promises real write once run everywhere including the UI
  • Flutter doesn't use any OS UI controls but paints everything with Skia
  • Flutter provides Widgets that exactly mimic the look of Material and iOS Controls
  • Flutter's core is written in C++ so it's really fast
  • You write Flutter programs using the language Dart which is AOT compiled into native code
  • It offers an instant reload function so that you can see any change you make to the App in moments on your device/emulator while the app's state is preserved
  • You program your UI not in some mark-up language like XAML but completely in code which sounds more cumbersome than it is as we will see.

Taking it to a test

Installation

Following the instruction on the Flutter.io page installation on Windows is pretty straight forward. I only had a complain about some Android SDK licences which could be fixed by creating a blank App in latest Android studio. Additionally I installed Dart Code the Dart and Flutter plugin for VS Studio Code.

If you install on Mac it can be a bit more work, so had I to upgrade to Mac OX High Sierra and also to update several tools which was ok because the Flutter installer tells you what is missing and how to install.

It just works

Opening the first sample and hit F5 in VS code and the app was build deployed and started without any problems. I was really surprised because I was no longer used to something like that.

One thing I should mention: when building for iOS you have to work on your Mac, you cannot remote build like with Xamarin

Let's write our own first Flutter program

I decided to port a small App that I did before in Xamarin forms. You can find the code here:

Into the Dar(k)t ages

Coming from C# I was surprised how easy it is to get accustomed with Dart the syntax is not so much different and on the Dart website you find all you need. I will point out interesting features of Dart when we get to code.

A Flutter Project

FlutterProjectStructure

This is a typical project structure of a Dart project. All your source files including main.dartare located in the lib folder. For now the only other interesting file is the pubspec.yaml where you register all packages that your project needs as well as all assets. Be careful, yaml files are very picky when you don't follow the correct indentation.

Widgets all around

Our goal is an UI like this:

mainscreen

Flutter builds it's UI completely through composition of Widgets that can again contain Widgets.
Yes, in Flutter everything is a Widget, even the App itself. As already mentioned the UI is completely build in code but compared with building a Page in Xamarin Forms this is very straight forward and with a little practice as good readable as a Xaml page.

Every widget has a build method that is responsible to create it's own subtree of widgets:

class HomePage extends StatelessWidget
 {
  @override
  Widget build(BuildContext context) {
      return 
         new Scaffold(  // A material control with an Appbar and a body
            appBar: new AppBar(title: new Text("WeatherDemo")),
            body: 
              new Column(children: <Widget>
              [
               new Padding(padding: const EdgeInsets.all(5.0),child: 
                      new TextField(
                              autocorrect: false,
                              decoration: new InputDecoration(
                                                  hintText: "Filter cities",
                                                  hintStyle: new TextStyle(color: new Color.fromARGB(150, 0, 0, 0)),
                                                  ),
                              style: new TextStyle(
                                            fontSize: 20.0,
                                            color: new Color.fromARGB(255, 0, 0, 0)),
                              onChanged: TheViewModel.of(context).OnFilerEntryChanged,),
                ),//Padding

                new Expanded( child: 
                      new WeatherListView(),  // Have to wrap the ListView into an Expanded otherwise the Column throws an exception
                    ),//Expanded

                new Padding(padding: const EdgeInsets.all(8.0),child: 
                      new MaterialButton(                               
                              child: 
                                new Text("Update"), // Watch the Button is again a composition
                              color: new Color.fromARGB(255, 33, 150, 243),
                              textColor: new Color.fromARGB(255, 255, 255, 255),
                              onPressed: TheViewModel.of(context).update
                              ),
                ), // Padding

              ],
            ),//Column
          );//Scaffold
  }

So our page is basically made of a Scaffold container with a Column which contains three "rows": A TextField, a ListView and a Button. The ListView was moved to its own Class so that the structure keeps readable.

As you see this is pretty straight forward. Decomposition in custom classes or just in a function is faster done than creating a custom view in Xamarin Forms.
Another advantage in using code to create your UI is that you can use code to dynamically create elements.

With Dart 2 it won't even be necessary to use new because the compiler will infer it automatically so that UI code looks nicer.

You may have wonder what this TheViewModel.of(context).update is. That's Flutter's way of providing a DataContext to the Widgets. For this you have to create an InheritedWidget that's only function is to propagate data down the widget tree from where it is placed in the tree. In this App I placed one at the very root of the tree so that all Widgets have access to my ViewModel.

Flutter Widgets are in principle stateless which means you cannot store any data in it as they will completely (not completely true) new created when refreshing the screen. One consequence is that we don't have permanent bindings between View and ViewModel that update automatically.

When I wrote in principle stateless this was not completely true. Besides the StatelessWidget above there are StatefullWidgets too that are made of a Widget and a State object. This State object is persistent during rebuilds of the UI and can so store information and subscribe to event handlers of view models.

Building the ListView

 WeatherListView();
    @override
    Widget build(BuildContext context) {
      return new StreamBuilder<List<WeatherEntry>>(   // Streambuilder rebuilds its subtree on every item the stream issues
              stream: TheViewModel.of(context).newWeatherEvents,   //We access our ViewModel through the inherited Widget
              builder: (BuildContext context, AsyncSnapshot<List<WeatherEntry>> snapshot)  // in Dart Lambdas with body don't use =>
                  {
                    // only if we get data
                    if (snapshot.hasData && snapshot.data.length > 0)
                    {
                        return new ListView.builder(
                                    itemCount: snapshot.data.length,
                                    itemBuilder : (BuildContext context, int index) => 
                                                      buildRow(context,index,snapshot.data)                                            
                                );//ListView
                    }
                    else
                    {
                      return new Text("No items");
                    }
                } // Builder function                                              
              );//Streambuilder

    }            

StreamBuilder is a nice Widget which will execute a builder method that rebuilds its widget subtree each time a new item is issued by a given Stream which allows a reactive design of your app. There is even a Dart version of Reactive Extensions that builds on top of Dart Streams.

This means every time the ViewModel pushes new data into the other side of the Stream the ListView will be recreated.

All collection widgets in Flutter exist in two versions. One that takes a predefined List of Items and a builder version that calls a handler every time it needs the data for a new row it wants to display which allows easy data virtualisation.

Moving the creation of the individual Rows into a separate function makes it again more maintainable:

Widget buildRow(BuildContext context, int index, List<WeatherEntry> listData) {
    return 
    new GestureDetector(
        child: 
            new Wrap(spacing: 40.0,
                children: <Widget>
                [
                    new Image(image: new NetworkImage(listData[index].iconURL)),

                    new Text(listData[index].cityName, style: new TextStyle(fontSize: 20.0))
                ],
                ),

        onTap: () => Navigator.push(context, 
                        new MaterialPageRoute( builder: (BuildContext context) => new DetailPage(listData[index])
                ))
    );

I hope this gives you a very first impression how UIs are build in Flutter

Conclusion

Having worked now for three weeks with Flutter I can say

Pros

  • Reliable Tool Chain
  • Designing in Code together with the instant reload is really fun and fast. Refactoring of widgets like decomposing into smaller units is just a cut and paste in a new file. Debugging is easier too because you have no symbolic bindings.
  • Exactly same look of your App on Android and iOS if you want. Soon automatic usage of platform like looking widgets will be available
  • No need for CustomRenders if you want to achieve more ambitious look and feel
  • A really huge and powerful library of Widgets that can be composed endlessly
  • Virtualized CollectionViews
  • Animations are very very easy. And they look on all platform the same.
  • Compared to a mark-up based framework the learning curve seems not as steep but this might come from my experience with Xamarin.
  • Non UI code of the app can be shared with web versions of it.
  • Fast build time
  • Very fast start-up time in release mode <2s
  • Runs as native compiled code
  • Very good API docs, examples and tutorial videos.

Cons

  • You cannot access native APIs directly from Dart. For that you have to write a plugin in either Java and Swift/Objective-C that communicates with your App through message channels
  • Currently not all device functions are available as plugins
  • The package library of Dart is nothing compared to the nuget universe
  • Currently no packages to use Azure, Firebase is there but who would have expect differently
  • Dart doesn't support reflection which is good for performance but make a lot of tasks tedious. For instance there is nothing compared to json.net or refit luckily for JSON there is a generator library that creates serialize and deserialize code for your classes.
  • Currently there are no established application frameworks like MvvmCross or similar. Overall there are only little resources on App architecture at the moment.
  • No remote building for iOS from a PC

Overall my subjective impression is that I'm much faster in creating appealing pages than in Xamarin Forms. It feels a bit more raw the way you code but also with more control because not so much happens automagically in the background.

Currently there is a huge hype around Flutter (20.000 stars on github) and if Google really launches Fuchsia it will be the default framework there. Which lets hope that missing plugins will soon be available.
On the other side it's still in beta and nobody know if Google may kill it before release.

My main reason for continuing with it is that I don't get continuously frustrated by the toolchain and the fast build times.

I can only recommend give it a try and see for yourself. Especially try the Flutter Gallery sample in the Flutter repo.

More information on [fluttering] (https://flutter.io)

On Gitter: gitter.im/flutter/flutter

Let me know what else do you want to know about Flutter!

Contact me:

9 thoughts on “Flutter – The new kid on the block

  1. Mario says:

    Nice blog post! I was about to ask to on twitter about this (How was your experience). Do you think (since it is still in beta) that it may be a good idea to start playing around with this as an alternative of Xamarin? I mean don’t get me wrong but I’ve been working with Xamarin.Forms for 3.5 years and I am thinking that it may be behind this new framework (in other words I am scared).

  2. CodeGrue says:

    I am very disappointed with the number of core controls in Xamarin.Forms. How can this library, far younger than Xamarin, already have like 5x the number of controls. And better looking. Frustrating.

  3. CodeGrue says:

    Can you post the source code? I would like to drill into how you build your ViewModel.

  4. Chris says:

    Hello,
    I’m anxiously waiting for “User Authentication the RxVMS way”.
    Any date in mind ?

    • Thomas Burkhart says:

      Sorry but I can’t say if this part will get realized as I’m too busy at the moment.

Leave a Reply

Your email address will not be published. Required fields are marked *