One of the most popular solutions for state management in Flutter is the BLoC pattern. BLoC stands for Business Logic Component and it's a design pattern that separates the business logic from the user interface. The main goal of BLoC is to manage the state of the app in a separate layer, making it easier to test and maintain the code over time.
One way to implement BLoC in Flutter is by using RxDart, a reactive programming library that allows you to create observables (streams) and react to their changes. In this tutorial, we'll create a simple app that uses BLoC for state management.
The first step is to create a new Dart file for our BLoC. Let's call it counter_bloc.dart. In this file, we need to define our BLoC class and its properties:
import 'package:rxdart/rxdart.dart';
class CounterBloc {
int _counter = 0;
final _counterSubject = BehaviorSubject();
Stream get counterStream => _counterSubject.stream;
void incrementCounter() {
_counter++;
_counterSubject.sink.add(_counter);
}
void dispose() {
_counterSubject.close();
}
}
In the code above, we have created our CounterBloc class that has an initial counter value of 0. We are using RxDart's BehaviorSubject to create a stream that represents the counter value over time. The counterStream getter allows us to access this stream from other parts of our app.
The incrementCounter method increments the counter and adds the new value to the stream using the BehaviorSubject's sink.add method.
Finally, the dispose method is called when the BLoC is no longer needed. This method closes the BehaviorSubject to avoid memory leaks.
Now that we have our CounterBloc, let's use it in a basic Flutter widget that displays the current counter value and a button to increment it:
import 'package:flutter/material.dart';
import 'counter_bloc.dart';
class CounterPage extends StatefulWidget {
@override
_CounterPageState createState() => _CounterPageState();
}
class _CounterPageState extends State {
final _counterBloc = CounterBloc();
@override
void dispose() {
_counterBloc.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Counter BLoC'),
),
body: Center(
child: StreamBuilder(
stream: _counterBloc.counterStream,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Counter: ${snapshot.data}'),
SizedBox(height: 16),
RaisedButton(
onPressed: _counterBloc.incrementCounter,
child: Text('Increment'),
),
],
);
} else {
return CircularProgressIndicator();
}
},
),
),
);
}
}
In the code above, we have created our CounterPage widget that instantiates the CounterBloc and then disposes of it when the widget is no longer needed. We are using a StreamBuilder widget to listen to the counterStream and update the UI accordingly. If the snapshot data is null, we'll display a loading indicator. Otherwise, we'll display the current counter value and a button that calls the incrementCounter method when pressed.
And that's pretty much it. With just a few lines of code, we have implemented the BLoC pattern with RxDart for state management in our Flutter app.