bloc_pattern 2.2.3

Bloc Pattern #

Donate

Tools to implement BLoC Pattern with Dependency Injection in your project

Start #

Add bloc_pattern in your pubspec.yaml.

Install in Flutter Web #

Temporarily, the codes for flutter_web have been separated from the main package. But in the future they will be one. To use the bloc_pattern in flutter_web add in your pubspec:

dependencies:
  bloc_pattern:
    git:
      url: https://github.com/jacobaraujo7/bloc-pattern.git
      ref: web

Using #

BLoC class #

Create the business logic class and extend to BlocBase

import 'package:bloc_pattern/bloc_pattern.dart';

class ValueBloc extends BlocBase {
  double value = 0.0;

  onChangeValue(double v) {
    value = v;
    notifyListeners();
  }
}

Now add the BlocProvider widget before MaterialApp

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      //add yours BLoCs controlles
      blocs: [
        Bloc((i) => ValueBloc()),
      ],
      //your main widget 
      child: MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: HomePage(),
      ),
    );
  }
}
...

You can search for a BLoC class anywhere in your application using:

    //recovering your Bloc
  final ValueBloc bloc = BlocProvider.getBloc<ValueBloc>();

Or consume directly on the Target widget using Consumer

    //Cosume your BLoC
  Consumer<ValueBloc>(
    builder: (BuildContext context, ValueBloc valueBloc) {
      return _textValue(valueBloc.value);
    },
  ),
  Container(
    height: 25,
  ),
  Consumer<ValueBloc>(
    builder: (BuildContext context, ValueBloc valueBloc) {
      return Slider(
      activeColor: Colors.white,
      inactiveColor: Colors.white,
      min: 0.0,
      max: 1.0,
      onChanged: valueBloc.onChangeValue,
      value: valueBloc.value);
    },
  ),

In this way, every time the ValueBloc onChangeValue method, the widgets inside the consumer will have new data. acesse o projeto completo clicando aqui.

Using Streams and Reactive Programming (Rx) #

You can also use the provider to get BlocClasses that work with streams for more complex processing using reactive programming.

import 'dart:async';
import 'package:bloc_pattern/bloc_pattern.dart';
import 'package:rxdart/rxdart.dart';

class BlocController extends BlocBase {

BlocController();

//Stream that receives a number and changes the count;
var _counterController = BehaviorSubject<int>.seeded(0);
//output
Stream<int> get outCounter => _counterController.stream;
//input
Sink<int> get inCounter => _counterController.sink;

increment(){
    inCounter.add(_counterController.value+1);
}

//dispose will be called automatically by closing its streams
@override
void dispose() {
  _counterController.close();
  super.dispose();
}

}

Add the Provider in the main widget of your widget tree by passing as your BlocController parameter


...

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      child: MaterialApp(
        home: IncrementWidget(),
      ),
      blocs: [
        //add yours BLoCs controlles
        Bloc((i) => BlocController()),
      ],
    );
  }
}

...

Now you can recover your Bloc anywhere in your widget tree with the help of BlocProvider


@override
  Widget build(BuildContext context) {
    //recovering your Bloc
  final BlocController bloc = BlocProvider.getBloc<BlocController>();

  ....


}

Now just use StreamBuilder to get your streams and change the UI without needing setState


StreamBuilder(
    stream: bloc.outCounter,
    builder: (BuildContext context, AsyncSnapshot snapshot) {
    return Text(
        '${snapshot.data}',
        style: Theme.of(context).textTheme.display1,
    );
    },
),

  ....

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


}

Dependency Injection #

Just like BLoC, you can also include in dependency injection other class. Ex: Services and Models


...

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      child: MaterialApp(
        home: IncrementWidget(),
      ),
      //add yours BLoCs controlles
       blocs: [
        Bloc((i) => IncrementController(i.get<GeneralApi>({"name":"John"}))),
        Bloc((i) => DecrementController())
      ],
      //add Other Object to provider
      dependencies: [
        Dependency((i) => GeneralApi(i.params['name'])),
      ],
    );
  }
}

...

You can define whether this dependency will behave as a singleton or not. Default is false.

For injection, use:


@override
  Widget build(BuildContext context) {
   
    //recovering your API dependency
  final GeneralApi api = BlocProvider.getDependency<GeneralApi>();
  
  //Passing Data by Parameters
  final UserModel user = BlocProvider.getDependency<UserModel>({
    "id": 1,
    "name": "João"
  });
  ....
}

Tag Module #

Now you can create other BlocProvider's independently. To do this use the "tag" property giving a name for your new BlocProvider segment.


...
  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      //tag module
      tag: "newModule",
  ...

From here you can call your blocks and dependency registered in your new module using:

    BlocProvider.tag("newModule").getBloc<BlocController>();

When you exit your tree of widget elements your BlocProvider will call the dispose () of that module only.X

ModuleWidget #

ModuleWidget uses the Tag Module implicitly, automating module creation for dependency injection. Basically creates a BlocProvider and the module tag is the name of the class itself. With this we can use the ModuleWidget instead of an instance of a StatelessWidget with the Widget of the BlocProvider using tag.

class HomeModule extends ModuleWidget {

  //Inject the blocs
  @override
  List<Bloc<BlocBase>> get blocs => [
        Bloc((i) => IncrementController())),
        Bloc((i) => DecrementController())
      ];

  //Inject the dependencies
  @override
  List<Dependency> get dependencies => [
        Dependency((i) => GeneralApi(i.params['name'])),
      ];

  //main widget
  @override
  Widget get view => HomeWidget();

  //shortcut to pick up dependency injections from this module
  static Inject get to => Inject<HomeModule>.of();

}

When using the Module Widget you do not have to worry about using tags, to access the module just use:

  //use
  HomeModule.to.bloc<HomeBloc>();
  //instead
  BlocProvider.tag("HomeModule").bloc<HomeBloc>();
  
  //using the Consumer pattern with widget ConsumerModule
  ConsumerModule<HomeBloc, HomeModule>(
    builder: (context, value){
      ...
    }
  ); 

Dispose #

The data is automatically discarded when the application finishes, however if you want to do this manually or restart some injected singleton, use:

//dispose BLoC
BlocProvider.disposeBloc<BlocController>();

//dispose dependency
BlocProvider.disposeDependency<GeneralApi>();


//dispose BLoC in Module
BlocProvider.tag("HomeModule").disposeBloc<BlocController>();

//dispose BLoC in ModuleWidget
HomeModule.to.disposeBloc<BlocController>();


[Optional] Add the dispose to your Bloc so that it can be called automatically or manually.


class YourBloc extends BlocBase {

  @override
  void dispose(){
    super.dispose
    //dispose Objects
  }
}

[Optional] Extend you Service or Repositore with Disposable for automatic dipose.


class GeneralApi extends Disposable {

  @override
  void dispose(){
    //dispose Objects
  }
}

THAT´S ALL

Para mais informações #

Acesse o Blog do Flutterando Clicando aqui.

2.2.3 (Jul 11, 2019) #

  • Fix error dispose unique bloc

2.2.2+3 (Jun 28, 2019) #

  • Add ConsumerModule

2.2.1 (Jun 22, 2019) #

  • Prepare to Slidy
  • Fix error inject module.

2.2.0+5 (Jun 21, 2019) #

  • Fix error consumer module.

2.2.0+4 (Jun 19, 2019) #

  • Fix error dispose bloc.

2.2.0+1 (Jun 14, 2019) #

  • Introduced project modules.
  • Tag for each BlocProvider. You can use multiple BlocProvider independently.

2.1.9+2 #

  • Fix dispose error

2.1.9 #

  • Add Consumer pattern.

2.1.7 #

  • Corrections in the parameters.

2.0.1 (May 1, 2019) #

  • BlocProvider and BlocProviderList are now one.
  • Added Injection of BLoC dependencies.
  • Added Injection Dependencies.

1.1.2 (December 8, 2018) #

  • removed context injection

1.1.1 (December 8, 2018) #

  • removed context injection

1.1.0 (November 19, 2018) #

  • Injected the context (BuildContext) into the controller.

1.0.0 (November 19, 2018) #

  • Support for Dart 2.1
  • Enhanced Bloc lifecycle with fast access anywhere in the application.

0.1.0 (November 8, 2018) #

  • Provider with StatefulWidget.

example/README.md

Bloc Pattern #

Donate

Tools to implement BLoC Pattern with Dependency Injection in your project

Start #

Add bloc_pattern in your pubspec.yaml.

BLoC class #

Create the business logic class and extend to BlocBase

import 'package:bloc_pattern/bloc_pattern.dart';

class ValueBloc extends BlocBase {
  double value = 0.0;

  onChangeValue(double v) {
    value = v;
    notifyListeners();
  }
}

Now add the BlocProvider widget before MaterialApp

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      //add yours BLoCs controlles
      blocs: [
        Bloc((i) => ValueBloc()),
      ],
      //your main widget 
      child: MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: HomePage(),
      ),
    );
  }
}
...

You can search for a BLoC class anywhere in your application using:

    //recovering your Bloc
  final ValueBloc bloc = BlocProvider.getBloc<ValueBloc>();

Or consume directly on the Target widget using Consumer

    //Cosume your BLoC
  Consumer<ValueBloc>(
    builder: (BuildContext context, ValueBloc valueBloc) {
      return _textValue(valueBloc.value);
    },
  ),
  Container(
    height: 25,
  ),
  Consumer<ValueBloc>(
    builder: (BuildContext context, ValueBloc valueBloc) {
      return Slider(
      activeColor: Colors.white,
      inactiveColor: Colors.white,
      min: 0.0,
      max: 1.0,
      onChanged: valueBloc.onChangeValue,
      value: valueBloc.value);
    },
  ),

In this way, every time the ValueBloc onChangeValue method, the widgets inside the consumer will have new data. acesse o projeto completo clicando aqui.

Using Streams and Reactive Programming (Rx) #

You can also use the provider to get BlocClasses that work with streams for more complex processing using reactive programming.

import 'dart:async';
import 'package:bloc_pattern/bloc_pattern.dart';
import 'package:rxdart/rxdart.dart';

class BlocController extends BlocBase {

BlocController();

//Stream that receives a number and changes the count;
var _counterController = BehaviorSubject<int>.seeded(0);
//output
Stream<int> get outCounter => _counterController.stream;
//input
Sink<int> get inCounter => _counterController.sink;

increment(){
    inCounter.add(_counterController.value+1);
}

//dispose will be called automatically by closing its streams
@override
void dispose() {
  _counterController.close();
  super.dispose();
}

}

Add the Provider in the main widget of your widget tree by passing as your BlocController parameter


...

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      child: MaterialApp(
        home: IncrementWidget(),
      ),
      blocs: [
        //add yours BLoCs controlles
        Bloc((i) => BlocController()),
      ],
    );
  }
}

...

Now you can recover your Bloc anywhere in your widget tree with the help of BlocProvider


@override
  Widget build(BuildContext context) {
    //recovering your Bloc
  final BlocController bloc = BlocProvider.getBloc<BlocController>();

  ....


}

Now just use StreamBuilder to get your streams and change the UI without needing setState


StreamBuilder(
    stream: bloc.outCounter,
    builder: (BuildContext context, AsyncSnapshot snapshot) {
    return Text(
        '${snapshot.data}',
        style: Theme.of(context).textTheme.display1,
    );
    },
),

  ....

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


}

Dependency Injection #

Just like BLoC, you can also include in dependency injection other class. Ex: Services and Models


...

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      child: MaterialApp(
        home: IncrementWidget(),
      ),
      //add yours BLoCs controlles
       blocs: [
        Bloc((i) => IncrementController(i.get<GeneralApi>({"name":"John"}))),
        Bloc((i) => DecrementController())
      ],
      //add Other Object to provider
      dependencies: [
        Dependency((i) => GeneralApi(i.params['name'])),
      ],
    );
  }
}

...

You can define whether this dependency will behave as a singleton or not. Default is false.

For injection, use:


@override
  Widget build(BuildContext context) {
   
    //recovering your API dependency
  final GeneralApi api = BlocProvider.getDependency<GeneralApi>();
  
  //Passing Data by Parameters
  final UserModel user = BlocProvider.getDependency<UserModel>({
    "id": 1,
    "name": "João"
  });
  ....
}

Dispose #

The data is automatically discarded when the application finishes, however if you want to do this manually or restart some injected singleton, use:

//dispose BLoC
BlocProvider.disposeBloc<BlocController>();

//dispose dependency
BlocProvider.disposeDependency<GeneralApi>();

[Optional] Add the dispose to your Bloc so that it can be called automatically or manually.


class YourBloc extends BlocBase {

  @override
  void dispose(){
    super.dispose
    //dispose Objects
  }
}

[Optional] Extend you Service or Repositore with Disposable for automatic dipose.


class GeneralApi extends Disposable {

  @override
  void dispose(){
    //dispose Objects
  }
}

THAT´S ALL

Para mais informações #

Acesse o Blog do Flutterando Clicando aqui.

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  bloc_pattern: ^2.2.3

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:bloc_pattern/bloc_pattern.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
96
Health:
Code health derived from static analysis. [more]
100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
100
Overall:
Weighted score of the above. [more]
98
Learn more about scoring.

We analyzed this package on Aug 20, 2019, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.4.0
  • pana: 0.12.19
  • Flutter: 1.7.8+hotfix.4

Platforms

Detected platforms: Flutter

References Flutter, and has no conflicting libraries.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.0.0-dev.68.0 <3.0.0
flutter 0.0.0
Transitive dependencies
collection 1.14.11 1.14.12
meta 1.1.6 1.1.7
sky_engine 0.0.99
typed_data 1.1.6
vector_math 2.0.8
Dev dependencies
flutter_test