bloc_pattern

Creator: coderz1093

Last updated:

Add to Cart

Description:

bloc pattern

Bloc Pattern #

Package that helps you implementing BloC Pattern by Dependency Injection in your project.
Package #
bloc_pattern
What is BloC? #
BLoC stands for Business Logic Components. The gist of BLoC is that everything in the app should be represented as stream of events: widgets submit events; other widgets will respond. BLoC sits in the middle, managing the conversation. It will be created separately from the view, isolating the logic of the code.
Why to use bloc_pattern? #
It's perfect to organize, and follow the best practices in your code, taking vantage of Dependency Injection. And it's the best package to use with slidy (created to structure your Flutter project).
How to implement? #
First step. #
Add bloc_pattern in your pubspec.yaml.
dependencies:

bloc_pattern: ^2.3.2

copied to clipboard
Or you can use slidy to add in your dependencies:
slidy install bloc_pattern

copied to clipboard
Starting to code #
1. #
Create the BloC class of your module, and extends from BlocBase.
import 'package:bloc_pattern/bloc_pattern.dart';
import 'package:rxdart/rxdart.dart';

class CounterBloc extends BlocBase{

Observable<int> counter; // observable (Stream)

CounterBloc() {
counter = Observable.merge([ //merges the both streams
_increment,
_decrement,
]).startWith(0) //starts with the value 0(the initial data)
.scan((acc, curr, i) => acc + curr, 0 /* inital value: 0 */) // scans the old(acc) and the current(curr) value, and sum them
.asBroadcastStream(); //turns the stream into a Broadcast straem(it can be listened to more than once)
}

final _increment = new BehaviorSubject<int>(); //the BehaviorSubject gets the last value
final _decrement = new BehaviorSubject<int>();

void increment() => _increment.add(1); //method to increment
void decrement() => _decrement.add(-1);//method to decrement


@override
void dispose() {// will be called automatically
_increment.close();
_decrement.close();
}

}
copied to clipboard
2. #
Now wrap your MaterialApp into a BlocProvider. Obs.: BlocProvider is the widget where you can Inject all the BloCs, and then recover them anywhere in your application.
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return BlocProvider(
blocs: [
Bloc((i) => CounterBloc()),
],
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
),
);
}
}
...
copied to clipboard
Recovering the BloC class. #
//recovering your BloC
final bloc = BlocProvider.getBloc<CounterBloc>();
copied to clipboard
Using StreamBuilder #
The StreamBuilder widgets lets you change the UI reactively without needing to call setState()(that rebuilds the stateful widget);
StreamBuilder(
stream: bloc.outCounter, //here you call the flux of data(stream)
builder: (BuildContext context, AsyncSnapshot snapshot) {
return Text(
'${snapshot.data}',
style: Theme.of(context).textTheme.display1,
);
},
),
copied to clipboard
Consuming the BloC directly from the Widget #
You can consume your BloC directly from the target Widget using the Consumer() class.
Everytime the CounterBloc adds a new value, the widgets within the Consumer will have new data.
You can see the project source code here.
BloC using Consume(): #
class CounterBloc {
...
int counter = 0;
onChanged(){
counter++;
notifyListeners(); //notifies when occurs a change
}

}

copied to clipboard
Consumer<CounterBloc>(
builder: (BuildContext context, CounterBloc bloc) {
return Text(bloc.counter.toString()); //calling the counter value
),
SizedBox(
height: 25.0,
),
Consumer<CounterBloc>(
builder: (BuildContext context, CounterBloc bloc) {
return
RaisedButton(
onPressed: () {
bloc.onChanged(); //calling onChanged() that will increment the value
},
child: Icon(Icons.add),
);
},
),
copied to clipboard
Dependency Injection #
You can also inject other dependencies aside BloC:
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'])), //repository
],
);
}
copied to clipboard
You can define if the dependency will be a Singleton or not:
Bloc((i) => CounterBloc(), singleton: false)
copied to clipboard
To inject the dependency in your class use:

@override
Widget build(BuildContext context) {

//recovering your API dependency
final GeneralApi api = BlocProvider.getDependency<GeneralApi>(); //repository

//Passing Data through parameters
final UserModel user = BlocProvider.getDependency<UserModel>({
"id": 1,
"name": "João"
});
....
}

copied to clipboard
Tags #
You can create new BlocProviders independently.

Use the property "tagText" giving a name for your new BlocProvider.
When you have more than one BlocProvider, you will need to use its tag to indentificate, otherwise it should return an error.


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

copied to clipboard
Calling the dependencies and BloCs from other classes:

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

copied to clipboard
ModuleWidget #
The ModuleWidget uses Tag Module in its structure:

Implicity creates a tag for the module class.
Gets automatically the tag when you call the module BloC.


You can use Slidy to create the module

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();

}
copied to clipboard
So instead of using BlocProvider and tags, you can just use ModuleWidget, it will also organize and modularize your project.
//use
HomeModule.to.bloc<HomeBloc>();
//instead of
BlocProvider.tag("HomeModule").bloc<HomeBloc>();

copied to clipboard
Dispose #
It's important to always call the dispose(), to make sure that the objects won't continue processing when you don't have any data.
The BlocBase already comes with Disposable, you just need to override it and will be called automatically in your ModuleWidget
class YourBloc extends BlocBase {

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

copied to clipboard
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>();

copied to clipboard
[Optional] Extends Disposable in your service or repository for automatic dispose.

class Repository extends Disposable {

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

copied to clipboard
Tests #
You can start your modules in the test environment and use dependency injections directly.
...
import 'package:flutter_test/flutter_test.dart';

void main() {
//start Module and Dependency Injection
initModule(AppModule());
AppBloc bloc;

setUp(() {
//get bloc
bloc = AppModule.to.bloc<AppBloc>();
});

group('AppBloc Test', () {
test("Counter Test", () {
expect(bloc.counter, 1);
});
test("Class Test", () {
expect(bloc, isInstanceOf<AppBloc>());
});
});
}

copied to clipboard
You can also override injection elements in initModule. Use this to replace your client with a Mock.
import 'package:flutter_test/flutter_test.dart';

class MockClient extends Mock implements Dio {}

void main() {
//start Module and Dependency Injection
initModule(AppModule(), changeDependencies: [
Dependency((i) => MockClient() as Dio),
]);
}

copied to clipboard
You can create your mocks based on the "BlocProvider.isTest" static property, which returns a boolean.
For more information #
Access Flutterando Blog.

License

For personal and professional use. You cannot resell or redistribute these repositories in their original state.

Customer Reviews

There are no reviews.