Book
  • Introduction
  • Welcome !!
  • Chapter 1: The mobile ecosystem
    • Fragmentation is the devil
    • There is more than one type of mobile app
    • ... more than one type of app
    • ... one type of app
    • Under pressure (ee da de da de) !!
    • Further reading!!
  • Chapter 2: Let's start with design thinking
    • A taste of design thinking
    • The five steps
    • Design for everybody
    • Accessibility in mobile apps
  • Chapter 3: Give me a context and I will give you an app
    • Users
    • Personas? Users ? What is the difference?
    • Please, help me to model the context
    • The context canvas
  • Chapter 4: Powerful models
    • Data architecture is the foundation of analytics
    • From data to information and knowledge
    • Information/Knowledge in our mobile ecosystem
    • Questions to ask yourselves when building and classifying questions
    • The visualization-data map
    • On the scene: describing how personas interact with your app
  • Chapter 5: A GUI is better than two thousand words
    • 'Good to Go:' Let's explore the Design Systems
    • Designing GUI Mocks
    • No prototype... no deal
  • Chapter 6: About mobile operating systems ... and other deamons
    • The Android OS ... son of LINUX
    • iOS son of Darwin? or is it iOS son of UNIX?
    • Kernels
  • Chapter 7: Yes, software architecture matters !!
    • Self-test time
    • About design and design constraints
    • Architects' mojo: styles and patterns
    • What you need is a tactic !!
    • Self-test time 2 (for real)
    • Further reading
  • Chapter 8: Finally... coding
    • MVC, MVVM, MV*, MV...What?
    • Programming models: the Android side
    • Hello Jetpack, my new friend... An Android Jetpack Introduction
    • Programming models: the iOS side
    • Controllers and more controllers
    • Flutter son of... simplicity
    • Programming models: Flutter?
    • Flutter: State matters... Let´s start simple
    • Flutter: State matters... Complex stuff ahead
    • Micro-optimizations
  • Chapter 9: Data pipeline
    • Generalities data pipelines
    • Data storage types
    • Types of data pipelines
  • Chapter 10: Error Retrieving Chapter 10
    • Eventual Connectivity on Mobile Apps
    • How to handle it on Android
  • Chapter 11: The jewel in the crown: Performance
    • As fast as a nail
    • Memory bloats
    • Energy leaks
    • Final thoughts
  • Chapter 12. Become a performance bugs exterminator
    • Weak or strong?
    • Micro-optimizations
    • The single thread game !!
    • Using multi-threading like a boss !!
    • Caching
    • Avoiding memory bloats
    • Further readings
Powered by GitBook
On this page
  • MobX
  • Store setup
  • Connecting to the store
  • Other awesome things
  • BLoC
  • Some examples
  1. Chapter 8: Finally... coding

Flutter: State matters... Complex stuff ahead

PreviousFlutter: State matters... Let´s start simpleNextMicro-optimizations

Last updated 1 year ago

(By Sergio Guzmán and Juan David Vega)


Similar to web development, Flutter also has state management techniques based on Flux Architecture and Async information gathering. Here we have two of the most famous ones from

MobX

Just like its web counterpart, MobX on dart uses a Flux-like architecture

Taken from https://mobx.netlify.com/concepts

Let´s start looking at this triad by explaining the process of integrating a store with the avalable resources from

Store setup

import 'package:mobx/mobx.dart';

// Include generated file
part 'counter.g.dart';

// This is the class used by rest of your codebase
class Counter = _Counter with _$Counter;

// The store-class
abstract class _Counter with Store {
  @observable
  int value = 0;

  @action
  void increment() {
    value++;
  }
}

Simple enough, a store is defined by to parts:

  • A codebase for the class with boilerplate code that supports the getters and setters of the values of the class ($_Counter)

  • An abstract class where observables (values that can change over time) and actions (methods to change the state of observables) are defined.

When first creating this class, the Flutter compiler will wonder where this "counter.g.dart" file is located. You only have to run the following command on the terminal to generate the file using mobx:

flutter packages pub run build_runner build

Connecting to the store

  • You need to instantiate the store outside your widget definition. Since MobX will handle the state of your app, your widgets will be Stateless.

  • Wherever you need the store data, put an Observer:

// Wrapping in the Observer will automatically re-render on changes to counter.value
Observer(
  builder: (_) => Text(
        '${counter.value}',
        style: Theme.of(context).textTheme.display1,
      ),
),
  • If you need to call an action, just use it as a regular method on your widgets

floatingActionButton: FloatingActionButton(
  onPressed: counter.increment,
  tooltip: 'Increment',
  child: Icon(Icons.add),
),

Other awesome things

  • You can play with computed values (state derived from your observables):

import 'package:mobx/mobx.dart';

part 'counter.g.dart';

class Contact = ContactBase with _$Contact;

abstract class ContactBase with Store {
  @observable
  String firstName;

  @observable
  String lastName;

  @computed
  String get fullName => '$firstName, $lastName';

}
  • You can also define reactions, that are event listener that get triggered when something happens to your observables. There are different flavors, like reacting to a specific value of the observable

import 'package:mobx/mobx.dart';

String greeting = Observable('Hello World');

final dispose = when((_) => greeting.value == 'Hello MobX', () => print('Someone greeted MobX'));

greeting.value = 'Hello MobX'; // Causes a change, runs effect and disposes


// Prints:
// Someone greeted MobX

BLoC

This pattern makes use of Streams. You define a stream to handle your state, and StreamBuilder widgets to consume from your stream.

In reality you have to worry abouth the sinking and streaming

Taken from https://www.raywenderlich.com/4074597-getting-started-with-the-bloc-pattern

When using the BLoC pattern you need to take into account three things:

  • Definition of a stream that can be consumed by other components. If you want to define a Stream we recommend you to create a StreamController of the specific type of object you want to consume and exposing the stream from the generated controller. Something like this:

  // 1
  final _myController = StreamController<MyClass>();

  // 2
  Stream<MyClass> get myClassStream => _myController.stream;
  • Always close the controller when you are done using the BLoC, meaning, _myController.close()

  • Use the StreamBuilder widget to attach a stream to the widget tree. There are three important properties for a StreamBuilder:

    • stream: A stream to consume

    • initialData: Start data for the stream

    • builder: Given the data (stored in snapshot) and the context (variables depending on the screen or app flow) render a specific widget

It´s better for you to look at a concrete example:

StreamBuilder<List<Restaurant>>(
    stream: bloc.favoritesStream,
    initialData: bloc.favorites,
    builder: (context, snapshot) {
      List<Restaurant> favorites =
          (snapshot.connectionState == ConnectionState.waiting)
              ? bloc.favorites
              : snapshot.data;
      if (favorites == null || favorites.isEmpty) {
        return Center(
          child: Text('No Favorites'),
        );
      }

      return ListView.separated(
        itemCount: favorites.length,
        separatorBuilder: (context, index) => Divider(),
        itemBuilder: (context, index) {
          final restaurant = favorites[index];
          return RestaurantTile(restaurant: restaurant);
        },
      );
    },
  )
  • Use sink when adding new data to the BLoC. This action will trigger a "data" event, meaning that something new was appended. This can be done easily from a StreamController

    //_myList is an array with ALL the data of your specific state of the BLoC
    _myController.sink.add(_myList);

Some examples

Also, if you are using Firebase Realtime database, then you might consider an approach based on this, since these kinds of databases are ultimately streams you can attach a StreamBuilder to, . You can also do more sophisticated subscriptions/streams management .

. This provides sample code and comparison for the three patterns.

. BLoC with Firestore.

Brian Kayfitz showcases a way in which you can organize your architecture using interfaces and inheritances inside a handson Restaurants example.

. Recipient of The Flutter Create code quality mention. You can check out this contest for .

. Short explanation of what MobX is and an example using observables and actions

like so
like this
Flutter app architecture 101: Vanilla, Scoped Model, BLoC
When Firebase meets BLoC Pattern
Flutter starting guide for BLoC
Building A Piano with Flutter
more inspiration
Flutter with MobX simple review app
the devs at Flutter
MobX dart
MobX Diagram
BLoC Diagram