First Glance at Flutter from an Android Native App Developer

30 Jan 2019, by Weiyi Li

Hero image weiyi flutter eb2b6ba2 efd8 4c34 a45c 932beea5d3cc

I made my decision to try Flutter last December after I saw the demo App "The History of Everything" at watching the Flutter 1.0 released video on YouTube, the animation was amazing, I am so touched.

As an Android App developer with several years of experience, I am most interested in two questions:

  • How can Flutter simplify development and make developers' lives easy?
  • Are there mature Android App solutions that are Flutter-equivalent?

The most effective way to learn is coding. So I started to convert few pages of an Android App I am working on to Flutter. The App is a typical List - Detail App contains several key points:

# Login Page          # List Page         # Detail Page
+---------------+    +---------------+    +---------------+
|               |    |[Tab1]2.3[Tab4]|    | Image         |
|    [Logo]     |    |---------------|    | Title         |
|               |    | item0         |    | SubTitle      |
|  [ name    ]  | => | item1         | => | Body......... |
|  [ password]  |    |   .           |    | ............. |
|               |    |   .           |    |               |
|     Login     |    |   .           |    |               |
|               |    | item(n)       |    |               |
+---------------+    +---------------+    +---------------+

During this process, I learned a couple of things:

  • how to build a screen.
  • how to build a tab navigation view.
  • how to build a list view.
  • how to navigate and pass data between screens.
  • how to restore data during screen rotation.
  • how to make http request.

The following screenshot is the login page which is written in Flutter runs on both iOS and Android:

BTW: Flutter society provides a lot of resources to learn, the official docs, demo Apps, YouTube channel, Medium articles. I will attach them at the end of this article.

How to Build a Screen: Screens are Just Widgets


As an Android developer, we might have the same experience in development:

  • (phase 1) Use Activity as a screen at the very beginning;
  • (phase 2) Then use Fragment as a screen, Activity is just used to host Fragments.

We might also struggle with the 2 LifeCycles of Fragment, the nested Fragments backstack, the screen rotation, the navigation between Fragments and Activities. Fortunately we have tools to simplify these problems, like ViewModel, LiveData, Data-binding, Navigation Graph & Controller, etc.

Flutter, as a new thing, seems to have no such historical burdens. Flutter claims that

Everything’s a Widget
https://flutter.io/docs/resources/technical-overview#everythings-a-widget

So does Screen. The following codes snippet builds a simple screen which contains an ActionBar and a Text. The full code contains a StatefulWidget which maintains state that might change during the lifetime of the widget, the state won't lost when rotate screen.

        Scaffold(
          appBar: AppBar(
            title: Text('Welcome to Flutter'),
          ),
          body: Center(
            child: Text('Hello Flutter'),
          )
        )

UI as Code: All in One Place


You might have realized that to build a screen all by codes is totally different from using XML & visual designer tools. Then you probably questioned how can we build a complicated screen without XML & visual designer tools? It happens to me as well at the very beginning but after writing few pages it has changed my mind and I start to like it because the view logic is all in one place instead of multiple places like Fragment, BindingAdapter, Layout xml, etc. However, All in One Place means a lot of UI codes and might be deeply nested syntax:

                                 )
                              ]),
                        ))
                      ],
                    ),
                  ),
                ],
              ),
            ));
      }
    }

But we can get rid of the nested syntax if we follow some rules:

(1). Name subexpressions instead of return A(B(C(D(), E())), F()). This turns the widget tree inside out, syntactically.
(2). Extract some meaningful pieces… Pieces? Widgets! Flutter widgets are all about composition and reuse.
Further reading Out of Depth with Flutter by Mikkel Ravn

How to Navigate and Pass Data Between Screens


In Flutter, Screens are Just Widgets, we can just simply pass data to the constructor of the destination widget:

    // https://flutter.io/docs/cookbook/navigation/passing-data
      Navigator.push(
        context,
        MaterialPageRoute(
          builder: (context) => DetailScreen(todo: todos[index]),
        ),
      );

Just a few lines of codes, that's it, fairly straightforward. No Intent, no Fragment Arguments, no Parcelable, no startActivity, no fragmentTransaction, no need to know so much details behind Activity and Fragment.

How to Build a List View


    // https://flutter.io/docs/cookbook/lists/long-lists
    ListView.builder(
      itemCount: items.length,
      itemBuilder: (context, index) {
        return ListTile(
          title: Text('${items[index]}'),
        );
      },
    );

Just a few lines of codes, no adapter, no item view-holder, no attaching adapter to list view.

Further reading: Flutter ListView and ScrollPhysics: A Detailed Look — Exploring the ListView Widget and its Features in Depth

How to Build a Tab Navigation


It's quite easy to implement tab navigation in both Material and Cupertino, just simply create the tabs and content for each tab, then set to TabController widget. Further reading Working with Tabs

Http & Async


It's the common practice to use Retrofit + Gson/Moshi + Data Class + Rx/Coroutines to implement API in nowadays. Are there any equivalents in Flutter?

The following codes snippet shows how I implement the login API in Flutter:

    /// api.dart //////////////////////////////////////////////////////////////////
    abstract class Api {
      Future<User> login(String email, String pwd);
    }

    /// user.dart /////////////////////////////////////////////////////////////////
    part 'user.g.dart';

    @JsonSerializable()
    class User {
      @JsonKey(name: 'id') int id;
      @JsonKey(name: 'name') String name;
      @JsonKey(name: 'email') String email;
      @JsonKey(name: 'auth_token') String authToken;

      User(this.id, this.name, this.email, this.authToken);
      factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
      Map<String, dynamic> toJson() => _$UserToJson(this);
    }

    /// repos.dart ////////////////////////////////////////////////////////////////
      @override
      Future<User> login(String email, String pwd) async {
        final response = await http.post(
          kApiLoginEndpoint,
          headers: {
            'Content-Type': 'application/json',
          },
          body: jsonEncode({
            'email': email,
            'password': pwd
          }),
        );
        if (response.statusCode == 200) {
          return User.fromJson(json.decode(response.body));;
        } else {
          throw ApiException(response.statusCode, response.reasonPhrase);
        }
      }

    /// login_page.dart ///////////////////////////////////////////////////////////
      void _login(String name, String pwd) {
        repos.login(name, pwd)
          .then((user) {
            print("Login succeed: $user");
          }).catchError((e) {
            print('Failed to login: ${e.toString()}');
        });
      }

The codes above are not well polished and have boilerplate codes. I still have some questions like:

  • How to log requests and responses?
  • Is there Retrofit's method(get, delete, post, put) annotations equivalent in Flutter?
  • How to intercept requests or responses to handle network status, API error, oAuth, header centralized?
  • How to implement type adapter factory? say if all the API response payloads are wrapped with data, like { "data": { ... } }
  • How to chain APIs like RxJava flatMap?

I found a 3rd package dio:

is a Http client for Dart, supports Interceptors, Global configuration, FormData, Request Cancellation, File downloading, Timeout etc.

I am not sure if it meets all the requirements but just give it a try.

Animation


I cannot say for sure, but Flutter animation looks quite simple at my first glance, compared the Hero animation in Flutter with the equivalent shared element transition animation in Android, just simply wrap the widgets with a Hero widget and set with the same tag, that's it! (As you see, "Everything’s a Widget" comes again).

Dart VS Kotlin


Dart doesn't have data class, sealed class, extension function, when expression, lack of null-safe types,... which Kotlin has, it's a pain, however, as a Java Dev, we know that language is just a tool, some fine to use, some not.

Others


How to learn


In Flutter, everything’s a widget. Flutter also provides a ton of widgets, to be honest, I almost get lost in composing widgets, but don't worry, there are several sample Apps that show the widget catalog: Flutter GalleryFlutter Catalog, Flutter Go.

Flutter Widget of the Week on YouTube contains a list of one-minute lovely videos showing how to use these widgets.

Search "Flutter cheat sheet" on Google you will get articles which are short, sweet and simple with loads of visual examples.

Flutter Codelabs provides a guided, tutorial, hands-on coding experience.

The official Flutter documentation is the most important, Get started part guide you set up the dev environment, Cookbook part contains recipes that demonstrate how to solve common problems while writing Flutter apps, each recipe is self-contained and provides complete code and running results in image or gif.

Summary


Flutter gives me a quite different experience compared with Android App development. I am not sure if it's the future, but just give it a try. You will probably also find different things.


Cookies help us deliver our services. By using our services, you agree to our use of cookies.