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

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. 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.
  2. Allow to pass a data Model from a parent Widget

    down to it's descendants (child). Ahmedabad Parent Child Child
  3. 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++; }); } }
  4. 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();
  5. 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: ), );
  6. 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
  7. 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
  8. 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")), ], ), ); } }
  9. ScopedModelDescendant<CounterModel>( builder: (context, child, model){ return }, ) return Center(

    child: Stack( children: <Widget>[ // Cart icon, Align( ... child: ), ], ), Text(model.counter.toString()); CardCount
  10. Business Logic • UI Independent • Rely on Streams •

    Platform independent • Environment independent • One or several BLoCs
  11. Conveyor Belt • is Stream • is data controrol by

    StreamController • is listeners
  12. 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(); }
  13. 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 },
  14. 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); },
  15. Step 3: Update Widgets final CounterBloc _counterBloc = CounterBloc(); ...

    return Scaffold( ... body: Center( child: StreamBuilder<int>(...), ), ); ... floatingActionButton: FloatingActionButton( onPressed: () { }, child: Icon(Icons.add), ), _counterBloc.incrementCount();
  16. 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);
  17. BlocBase abstract class BlocBase { void dispose(); } class CounterBloc

    implements BlocBase { ... @override void dispose() { _counterController.close(); } ... }
  18. 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 ... }
  19. 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