Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Build Reactive Architecture in Flutter

Build Reactive Architecture in Flutter

In this talk, we will learn and share my experience on What is reactive architecture with few architecture solution like Redux, Scoped Model and BLoC Pattern also will share a case study of my WhatTodo app.

Burhanuddin Rashid

September 29, 2019
Tweet

More Decks by Burhanuddin Rashid

Other Decks in Programming

Transcript

  1. Build Reactive Architecture In
    Flutter
    Burhanuddin Rashid

    View full-size slide

  2. What is Architecture ?

    View full-size 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 full-size slide

  4. Separation of Concerns

    View full-size slide

  5. Expectations

    View full-size slide

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

    View full-size slide

  7. Architecture in Flutter
    ● Redux
    ● Provider
    ● Mobx
    ● Scoped Model
    ● BLoC

    View full-size slide

  8. Architecture in Flutter
    ● Redux
    ● Provider
    ● Mobx
    ● Scoped Model
    ● BLoC

    View full-size slide

  9. Architecture in Flutter
    ● Redux
    ● Provider
    ● Mobx
    ● Scoped Model
    ● BLoC

    View full-size slide

  10. Architecture in Flutter
    ● Redux
    ● Provider
    ● Mobx
    ● Scoped Model
    ● BLoC

    View full-size slide

  11. Scoped Model

    View full-size slide

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

    View full-size slide

  13. 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 full-size slide

  14. Building complex app is
    never easy

    View full-size slide

  15. Let’s see the code

    View full-size slide

  16. Step 1: Add Dependency
    pubspec.yaml
    dependencies:
    scoped_model: ^1.0.1

    View full-size slide

  17. 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 full-size slide

  18. 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 full-size slide

  19. 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 full-size slide

  20. 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 full-size slide

  21. 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 full-size slide

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

    View full-size slide

  23. Rebuild all the
    ScopedModelDescendant<> Widgets

    View full-size slide

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

    View full-size slide

  25. BLoC
    Business Logic Component

    View full-size slide

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

    View full-size slide

  27. What is Streams ?

    View full-size slide

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

    View full-size slide

  29. New Delhi
    Conveyor Belt

    View full-size slide

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

    View full-size slide

  31. Let’s see the code

    View full-size slide

  32. 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 full-size slide

  33. 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 full-size slide

  34. 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 full-size slide

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

    View full-size slide

  36. Problem
    Need to create BLoC for every
    widget

    View full-size slide

  37. BlocProvider

    View full-size slide

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

    View full-size slide

  39. 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 full-size slide

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

    View full-size slide

  41. 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 full-size slide

  42. New Delhi
    Create Task Create Project Create Label

    View full-size slide

  43. 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 full-size slide

  44. Burhanuddin Rashid, Technogise
    @burhanrashid52
    Thank you!
    Does anyone have any questions ?
    https://burhanrashid52.com

    View full-size slide