0
0
Fluttermobile~5 mins

BLoC pattern basics in Flutter

Choose your learning style9 modes available
Introduction

The BLoC pattern helps separate your app's logic from its user interface. This makes your app easier to manage and test.

When you want to keep your UI code simple and clean.
When your app has multiple screens sharing data.
When you want to handle user actions and update UI reactively.
When you want to write tests for your app's logic without UI.
When you want to organize your app for easier maintenance.
Syntax
Flutter
import 'dart:async';

class CounterBloc {
  final _counterController = StreamController<int>.broadcast();
  int _counter = 0;

  Stream<int> get counterStream => _counterController.stream;

  void increment() {
    _counter++;
    _counterController.sink.add(_counter);
  }

  void dispose() {
    _counterController.close();
  }
}

The BLoC class holds your app's logic and data.

Use Streams to send data updates to the UI.

Examples
This example shows how to use the BLoC to increment a counter and listen for updates.
Flutter
final bloc = CounterBloc();
bloc.increment();
bloc.counterStream.listen((count) {
  print('Count is $count');
});
This shows how to connect the BLoC stream to the UI using StreamBuilder.
Flutter
StreamBuilder<int>(
  stream: bloc.counterStream,
  builder: (context, snapshot) {
    final count = snapshot.data ?? 0;
    return Text('Count: $count');
  },
);
Sample App

This app shows a number on screen that increases each time you press the button. The BLoC handles the counting logic and updates the UI through a stream.

Flutter
import 'dart:async';
import 'package:flutter/material.dart';

class CounterBloc {
  final _counterController = StreamController<int>.broadcast();
  int _counter = 0;

  Stream<int> get counterStream => _counterController.stream;

  void increment() {
    _counter++;
    _counterController.sink.add(_counter);
  }

  void dispose() {
    _counterController.close();
  }
}

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  final CounterBloc bloc = CounterBloc();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('BLoC Pattern Example')),
        body: Center(
          child: StreamBuilder<int>(
            stream: bloc.counterStream,
            initialData: 0,
            builder: (context, snapshot) {
              return Text('Count: ${snapshot.data}', style: TextStyle(fontSize: 30));
            },
          ),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: bloc.increment,
          child: Icon(Icons.add),
          tooltip: 'Increment',
        ),
      ),
    );
  }
}
OutputSuccess
Important Notes

Always close your StreamControllers by calling dispose() to avoid memory leaks.

Use StreamBuilder in the UI to listen and rebuild widgets when data changes.

BLoC helps keep your UI code simple and your logic reusable.

Summary

BLoC separates app logic from UI using streams.

Use StreamController to manage data flow.

StreamBuilder connects streams to UI widgets.