Exploring the new kid on the block: Flutter

Victor Lap Victor Lap
23 - 05 - 2018

Working at a tech company, keeping up with recent developments in the field is a must. As such, when Flutter beta1 was released on februari 27th, I decided to take a look. Here are my findings.

What is Flutter

From the official site: “Flutter is Google’s mobile UI framework for crafting high-quality native interfaces on iOS and Android in record time. “ Having worked with multiple cross-platform app toolkits like Ionic, Cordova and later react native, I knew that cross-platform tools are, more often than not, slow and a pain to work with compared to the development experience of native apps. I knew that Flutter would have to bring a lot to the table to live up to their not so humble expectations.

Flutter is based around Google’s programming language Dart. Dart is a clear and concise statically typed language, which looks a lot like C# or Java. As such, app developers probably have a low learning curve when it comes to learning Dart. The dart code is compiled to native code. Flutter does not use the native components, but instead provides their own. That is part of the reason why flutter is blazing fast compared to other cross-platform tools.

Test drive

To fully test Flutter, I wanted to implement a simple app. Flutter supports VS Code, IntelliJ and Android Studio to develop Flutter apps, I am using Android Studio. The project I want to build is a personal bookshelf. I want to use it to keep track of the books I have read, thus the app should support a list of all the books and a way to add them. The app is made using Firebase to persist the data and the Google Books API.

After having installed the toolkit, we can start a new flutter project through the ‘Start a new Flutter Project’ window. Click on Flutter Application, choose a name for your app and fill in the other details.

We first need to define the model for our books application. We want to show the user the title, the author, a description and an image. The beauty of dart is the first thing that you can notice. Instead of having to explicitly declare the constructor, you only define the constructor arguments, and dart does the rest for you.

                                        class Book {
  final String id;
  final String title;
  final String author;
  final String description;
  final String thumb;
  Book(this.id, this.title, this.author, this.description, this.thumb);
}
                                    

Next up we are going to add the google api dependency, so we can fetch books from the api. Flutter makes use of the excellent dependency system that dart provides, this can be accessed at https://pub.dartlang.org where you can find both dart packages, and specific flutter packages. Luckily the documentation is up to date, the only thing we need is to add two dependencies to our pubspec.yaml file and run flutter packages get to get all dependencies.

                                    dependencies: 
   flutter:
     sdk: flutter
+  googleapis: any
+  googleapis_auth: any
                                

Next, we add a little method to return us a list of books when we search for a title. There is a small error in the API at the moment of writing, so I needed to change some core.List<core.String>to core.List<core.dynamic> for authors (line 8429) and categories (line 8438) in googleapis-0.50.1/lib/books/v1.dart.

                                        import ...

class GoogleApi {
  static const _SCOPES = const [BooksApi.BooksScope];
  static Future<Volumes> search(q) {
    return clientViaServiceAccount(gccCredentials, _SCOPES).then((httpClient) {
      var books = new BooksApi(httpClient);
      return books.volumes.list(q);
    });
  }
}
                                    

The next thing we can do is show the results we get from Google. But first we need an input method.

                                    new TextField(
  decoration: new InputDecoration(
  hintText: 'Search for a book',
)
                                

After the input fields has been added, we can implement an on change listener which will fire a search request. When the on change listener is fired, we first search for books using the api and when they are returned we populate a list, we call setState() afterwards to refresh the ui. This list is then displayed using a ListView.builder . For now we just display the title. Container() is Flutters way of saying that there should be some empty space.

                                        void _onChanged(text) {
  if (text == "") {
    return;
  }
  var results = search(text);
  results.then((results) {
    _books = [];
    for (var _volume in results.items) {
      _books.add(Book.fromVolume(_volume));
    }
    setState(() {});
  });
}
Widget _buildBookList(List<Book> books) {
  if (books == null) {
    return new Container();
  }
  return new ListView.builder(
    itemBuilder: (BuildContext context, int index) {
      new ListTile(
        title: new Text(books[index].title),
      );
    },
    itemCount: books.length,
  );
}
                                    

We can now search for books and see the results on the screen, but it would be nice if we could see a little more info. For this we make an extra screen with the details of the books. I have also added a little extra information to each book tile. Flutter uses a simple approach to navigation, where you can push and pop Widgets of the stack.

                                    void _onTapped(Book book) {
  Navigator.push(
    context,
    new MaterialPageRoute(builder: (context) => new BookScreen(book)),
  );
}
                                

By now we can search for, and see details of a book. To save the books to a list, we have to add a kind of database. We will add firebase for this purpose. Using Codelabs we can see how we can setup firebase for our app. Firebase uses platform specific ways of finding your API keys, so follow the codelab to add your API key for either Android or iOS.

                                        import 'package:firebase_database/firebase_database.dart';

class FirebaseApi {
  static final reference = FirebaseDatabase.instance.reference();
  static final bookRef = reference.child('books');
}
                                    

By now we have added a screen where we can list our favourite books, however, we do not currently have a way to mark a book as favourite, so let’s implement that. For the finishing touch it is nice to see whether a book is favourited or not, so we need to switch the book tile from stateless widget to stateful widget, and also add the possibility that a book is no longer a favourite.

                                    class FirebaseApi {
  ...
  static void addBook(Book book) {
    bookRef.child(book.id).set(book.toJson());
  }
  static void removeBook(Book book) {
    reference.child(book.id).remove();
  }
}
Widget build(BuildContext context) {
  return new ListTile(
    ...
    trailing: new IconButton(
      icon: new Icon(Icons.favorite),
      color: _favourite ? Colors.red : null,
      onPressed: _onFavourite,
   ),  
  );
}
...
void _onFavourite() {
  if (_favourite) {
    FirebaseApi.removeBook(_book);
  } else {
    FirebaseApi.addBook(_book);
  }
  setState(() {
    _favourite = !_favourite;
  });
}
                                

Findings

With the new beta2 release, the Flutter team has delivered a strong foundation for the framework. It is very easy to implement simple apps, but they provide a rich api of which you can customise all widgets. There are some small details that do not work as expected, but I think when version 1.0 is released, everything will be fixed. I think Flutter is at this moment not mature enough to use it for production apps, but it will be very soon!

Resources:

Source code is available at :

Victor Lap. As a backend developer Victor loves to build native apps. Victor Lap. As a backend developer Victor loves to build native apps.

Deel deze blog

Jouw partner voor digitalisering  en  automatisering

Bedankt voor je bericht! We nemen z.s.m. contact met je op. :)
We willen graag je naam en e-mailadres weten om contact op te kunnen nemen.

Laten we samen een keer brainstormen of vertel ons wat over jouw uitdaging. Laat je gegevens achter en we nemen z.s.m. contact met je op.