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.

37a2dd0f4a7e7c8584658f36d07e1e33?s=128

Burhanuddin Rashid

November 26, 2018
Tweet

Transcript

  1. Reactive Architecture in Flutter Burhanuddin Rashid Technogise @burhanrashid52

  2. What is Architecture ?

  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.
  4. Ahmedabad

  5. Separation of Concerns

  6. Expectations

  7. Reality

  8. Reactive

  9. Ahmedabad

  10. Reactive • Asynchronous data streams • Events • Triggers by

    data streams • Notify Listeners
  11. Architecture in Flutter • Redux • Scoped Model • BLoC

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

  13. Scoped Model

  14. Allow to pass a data Model from a parent Widget

    down to it's descendants (child). Ahmedabad Parent Child Child
  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<MyHomePage> { int _counter = 0; void _incrementCounter() { setState(() { _counter++; }); } }
  16. Building complex app is never easy

  17. Let’s see the code

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

  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();
  20. Step 3: Add Scope Model class MyApp extends StatelessWidget {

    @override Widget build(BuildContext context) { return } } MaterialApp( debugShowCheckedModeBanner: false, home: HomePage(), model: CounterModel(), ScopedModel<CounterModel>( child: ), );
  21. Step 4: Add Scope Model Descendant class HomePage extends StatelessWidget

    { ... return Scaffold( ... body: Center( child: ), floatingActionButton:..., ); } ScopedModelDescendant<CounterModel>( }, ), Text(model.counter.toString(), style: Theme.of(context).textTheme.display1); builder: (context, child, model) { return
  22. Step 5: Update Scope Model Descendant return Scaffold( ... body:

    Center(...), ... floatingActionButton: ); ScopedModelDescendant<CounterModel>( }, ), FloatingActionButton( onPressed: () { model.increment(); }, child: Icon(Icons.add), ); builder: (context, child, model) { return
  23. Demo

  24. None
  25. Pros

  26. Independent Widget return Scaffold( appBar: AppBar( title: Text("Scope Model"), actions:

    <Widget>[CartCount()], ), body:(...), floatingActionButton: ScopedModelDescendant<CounterModel>( ... ), ); class CartCount extends StatelessWidget { @override Widget build(BuildContext context) { return Center( child: Stack( children: <Widget>[ // Cart icon, Align( ... child:Text("1")), ], ), ); } }
  27. ScopedModelDescendant<CounterModel>( builder: (context, child, model){ return }, ) return Center(

    child: Stack( children: <Widget>[ // Cart icon, Align( ... child: ), ], ), Text(model.counter.toString()); CardCount
  28. None
  29. Cons

  30. Rebuild all the ScopedModelDescendant<> Widgets

  31. None
  32. Disabled rebuild ScopedModelDescendant<CounterModel>( rebuildOnChange: false, builder:..., )

  33. BLoC Business Logic Component

  34. Business Logic • UI Independent • Rely on Streams •

    Platform independent • Environment independent • One or several BLoCs
  35. What is Streams ?

  36. Conveyor Belt • is Stream • is data controrol by

    StreamController • is listeners
  37. Ahmedabad Conveyor Belt

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

  39. Let’s see the code

  40. Step 1: Create BLoC class CounterBloc { int _counter =

    0; void incrementCount() { _counter++; } } StreamController<int> _counterController = StreamController<int>.broadcast(); Stream<int> get outCounter => _counterController.stream; _counterController.sink.add(_counter); void dispose() { _counterController.close(); }
  41. Step 2: Adding StreamBuilder<T> StreamBuilder<T>( ) key: // Optional, the

    unique ID of this Widget... stream: // The stream to listen to... initialData: // Any initial data builder: (BuildContext context, AsyncSnapshot<T> snapshot){ if (snapshot.hasData){ return // Widget to be built based on snapshot.data } return // Widget to be built if no data is available },
  42. Step 2: Adding StreamBuilder<T> @override Widget build(BuildContext context) { return

    Scaffold( ... body: Center( child: StreamBuilder<int>( )... final CounterBloc _counterBloc = CounterBloc(); initialData: 0, stream: _counterBloc.outCounter, builder: (context, snapshot) { return Text(snapshot.data.toString(), style: Theme.of(context).textTheme.display1); },
  43. Step 3: Update Widgets final CounterBloc _counterBloc = CounterBloc(); ...

    return Scaffold( ... body: Center( child: StreamBuilder<int>(...), ), ); ... floatingActionButton: FloatingActionButton( onPressed: () { }, child: Icon(Icons.add), ), _counterBloc.incrementCount();
  44. Demo

  45. None
  46. Problem Need to create BLoC for every widget

  47. BlocProvider

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

  49. Generic BlocProvider class BlocProvider<T extends BlocBase> extends StatefulWidget { }

    final T bloc; final Widget child; BlocProvider({ Key key, @required this.child, @required this.bloc, }): super(key: key);
  50. BlocBase abstract class BlocBase { void dispose(); } class CounterBloc

    implements BlocBase { ... @override void dispose() { _counterController.close(); } ... }
  51. Implementation MaterialApp( home: BlocProvider( bloc: CounterBloc(), child: MyHomePage(), ), )

    class MyHomePage extends StatelessWidget { @override Widget build(BuildContext context) { CounterBloc _counterBloc = BlocProvider.of<CounterBloc>(context); return .. } class CartCount extends StatelessWidget { @override Widget build(BuildContext context) { CounterBloc _counterBloc = BlocProvider.of<CounterBloc>(context); return ... }
  52. Demo

  53. None
  54. Ahmedabad

  55. WhatTodo

  56. Ahmedabad Create Task Create Project Create Label

  57. Ahmedabad

  58. Ahmedabad

  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
  60. Burhanuddin Rashid, Technogise @burhanrashid52 Thank you!

  61. None
  62. None
  63. Q&A https://burhanrashid52.github.io