$30 off During Our Annual Pro Sale. View Details »

Build Reactive Architecture in Flutter

Build Reactive Architecture in Flutter

Flutter uses reactive views, which you can take to the next level by applying reactive principles with BLoC and ScopedModel patterns to your app’s data model.

Burhanuddin Rashid

November 26, 2018
Tweet

More Decks by Burhanuddin Rashid

Other Decks in Technology

Transcript

  1. Reactive Architecture in
    Flutter
    Burhanuddin Rashid
    Technogise
    @burhanrashid52

    View Slide

  2. What is Architecture ?

    View Slide

  3. Architecture
    Software architecture refers to the high level structures of a software
    system and the discipline of creating such structures and systems. Each
    structure comprises software elements, relations among them, and
    properties of both elements and relations. The architecture of a software
    system is a metaphor, analogous to the architecture of a building. It
    functions as a blueprint for the system and the developing project, laying
    out the tasks necessary to be executed by the design teams.

    View Slide

  4. Ahmedabad

    View Slide

  5. Separation of Concerns

    View Slide

  6. Expectations

    View Slide

  7. Reality

    View Slide

  8. Reactive

    View Slide

  9. Ahmedabad

    View Slide

  10. Reactive
    ● Asynchronous data streams
    ● Events
    ● Triggers by data streams
    ● Notify Listeners

    View Slide

  11. Architecture in Flutter
    ● Redux
    ● Scoped Model
    ● BLoC

    View Slide

  12. Architecture in Flutter
    ● Redux
    ● Scoped Model
    ● BLoC

    View Slide

  13. Scoped Model

    View Slide

  14. Allow to pass a data
    Model from a parent
    Widget down to it's
    descendants (child).
    Ahmedabad
    Parent
    Child Child

    View Slide

  15. Counter Example
    ...
    return Scaffold(
    ...
    body: Center(
    child: Text('$_counter', style:
    Theme.of(context).textTheme.display1),
    ),
    floatingActionButton: FloatingActionButton(
    onPressed: _incrementCounter,
    child: Icon(Icons.add),
    ),
    );
    ...
    class _MyHomePageState extends
    State {
    int _counter = 0;
    void _incrementCounter() {
    setState(() {
    _counter++;
    });
    }
    }

    View Slide

  16. Building complex app is
    never easy

    View Slide

  17. Let’s see the code

    View Slide

  18. Step 1: Add Dependency
    pubspec.yaml
    dependencies:
    scoped_model: ^0.3.0

    View Slide

  19. Step 2: Create a Model
    class CounterModel {
    int _counter = 0;
    int get counter => _counter;
    void increment() {
    // First, increment the counter
    _counter++;
    }
    }
    extends Model
    // Then notify all the listeners.
    notifyListeners();

    View Slide

  20. Step 3: Add Scope Model
    class MyApp extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
    return
    }
    }
    MaterialApp(
    debugShowCheckedModeBanner: false,
    home: HomePage(),
    model: CounterModel(),
    ScopedModel(
    child:
    ),
    );

    View Slide

  21. Step 4: Add Scope Model Descendant
    class HomePage extends StatelessWidget {
    ...
    return Scaffold(
    ...
    body: Center(
    child:
    ),
    floatingActionButton:...,
    );
    }
    ScopedModelDescendant(
    },
    ),
    Text(model.counter.toString(),
    style: Theme.of(context).textTheme.display1);
    builder: (context, child, model) {
    return

    View Slide

  22. Step 5: Update Scope Model Descendant
    return Scaffold(
    ...
    body: Center(...),
    ...
    floatingActionButton:
    );
    ScopedModelDescendant(
    },
    ),
    FloatingActionButton(
    onPressed: () {
    model.increment();
    },
    child: Icon(Icons.add),
    );
    builder: (context, child, model) {
    return

    View Slide

  23. Demo

    View Slide

  24. View Slide

  25. Pros

    View Slide

  26. Independent Widget
    return Scaffold(
    appBar: AppBar(
    title: Text("Scope Model"),
    actions: [CartCount()],
    ),
    body:(...),
    floatingActionButton:
    ScopedModelDescendant(
    ...
    ),
    );
    class CartCount extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
    return Center(
    child: Stack(
    children: [
    // Cart icon,
    Align(
    ...
    child:Text("1")),
    ],
    ),
    );
    }
    }

    View Slide

  27. ScopedModelDescendant(
    builder: (context, child, model){
    return
    },
    )
    return Center(
    child: Stack(
    children: [
    // Cart icon,
    Align(
    ...
    child:
    ),
    ],
    ),
    Text(model.counter.toString());
    CardCount

    View Slide

  28. View Slide

  29. Cons

    View Slide

  30. Rebuild all the
    ScopedModelDescendant<> Widgets

    View Slide

  31. View Slide

  32. Disabled rebuild
    ScopedModelDescendant(
    rebuildOnChange: false,
    builder:...,
    )

    View Slide

  33. BLoC
    Business Logic Component

    View Slide

  34. Business Logic
    ● UI Independent
    ● Rely on Streams
    ● Platform independent
    ● Environment independent
    ● One or several BLoCs

    View Slide

  35. What is Streams ?

    View Slide

  36. Conveyor Belt
    ● is Stream
    ● is data controrol by StreamController
    ● is listeners

    View Slide

  37. Ahmedabad
    Conveyor Belt

    View Slide

  38. Step 1: Add Dependency
    pubspec.yaml
    dependencies:
    rxdart: ^0.19.0

    View Slide

  39. Let’s see the code

    View Slide

  40. Step 1: Create BLoC
    class CounterBloc {
    int _counter = 0;
    void incrementCount() {
    _counter++;
    }
    }
    StreamController _counterController =
    StreamController.broadcast();
    Stream get outCounter => _counterController.stream;
    _counterController.sink.add(_counter);
    void dispose() {
    _counterController.close();
    }

    View Slide

  41. Step 2: Adding StreamBuilder
    StreamBuilder(
    )
    key: // Optional, the unique ID of this Widget...
    stream: // The stream to listen to...
    initialData: // Any initial data
    builder: (BuildContext context, AsyncSnapshot snapshot){
    if (snapshot.hasData){
    return // Widget to be built based on snapshot.data
    }
    return // Widget to be built if no data is available
    },

    View Slide

  42. Step 2: Adding StreamBuilder
    @override
    Widget build(BuildContext context) {
    return Scaffold(
    ...
    body: Center(
    child: StreamBuilder(
    )...
    final CounterBloc _counterBloc = CounterBloc();
    initialData: 0,
    stream: _counterBloc.outCounter,
    builder: (context, snapshot) {
    return Text(snapshot.data.toString(),
    style: Theme.of(context).textTheme.display1);
    },

    View Slide

  43. Step 3: Update Widgets
    final CounterBloc _counterBloc = CounterBloc();
    ...
    return Scaffold(
    ...
    body: Center(
    child: StreamBuilder(...),
    ),
    );
    ...
    floatingActionButton: FloatingActionButton(
    onPressed: () {
    },
    child: Icon(Icons.add),
    ),
    _counterBloc.incrementCount();

    View Slide

  44. Demo

    View Slide

  45. View Slide

  46. Problem
    Need to create BLoC for every
    widget

    View Slide

  47. BlocProvider

    View Slide

  48. Didier Boelens
    https://medium.com/@boeledi

    View Slide

  49. Generic BlocProvider
    class BlocProvider extends StatefulWidget {
    }
    final T bloc;
    final Widget child;
    BlocProvider({
    Key key,
    @required this.child,
    @required this.bloc,
    }): super(key: key);

    View Slide

  50. BlocBase
    abstract class BlocBase {
    void dispose();
    }
    class CounterBloc implements BlocBase {
    ...
    @override
    void dispose() {
    _counterController.close();
    }
    ...
    }

    View Slide

  51. Implementation
    MaterialApp(
    home: BlocProvider(
    bloc: CounterBloc(),
    child: MyHomePage(),
    ),
    )
    class MyHomePage extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
    CounterBloc _counterBloc = BlocProvider.of(context);
    return ..
    }
    class CartCount extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
    CounterBloc _counterBloc = BlocProvider.of(context);
    return ...
    }

    View Slide

  52. Demo

    View Slide

  53. View Slide

  54. Ahmedabad

    View Slide

  55. WhatTodo

    View Slide

  56. Ahmedabad
    Create Task Create Project Create Label

    View Slide

  57. Ahmedabad

    View Slide

  58. Ahmedabad

    View Slide

  59. Resources
    ● Didier Boelens blog
    https://www.didierboelens.com/2018/08/reactive-programming---streams--
    -bloc/
    ● Scope Model
    https://pub.dartlang.org/packages/scoped_model
    ● WhatTodo
    https://github.com/burhanrashid52/WhatTodo
    ● Scope Model Example : https://bit.ly/2Q5gEQN
    ● BLoC Example : https://bit.ly/2OQs2ve
    ● Bloc Provider Example : https://bit.ly/2DJYsq9
    ● MTechViral : https://bit.ly/2Sb5isS

    View Slide

  60. Burhanuddin Rashid, Technogise
    @burhanrashid52
    Thank you!

    View Slide

  61. View Slide

  62. View Slide

  63. Q&A
    https://burhanrashid52.github.io

    View Slide