August 14, 2021

How to use BLoC architecture in flutter – 1

By lj007

BloC architecture – BloC is short form for Business Logic Component. As it name suggest, we will use it for separating business logic from presentation logic.created by Felix Angelov and was introduced at Google I/O in 2019. Hence Bloc is not architecture itself, we still need to organize our data according to DDD, MVVM or other.

We will not discuss Pros and Cons here, We will move straight to its implementation in our flutter app.

BloC architecture components

  • Event And Actions are input that appears when user interacts with app, like button click or scroll
  • State is reaction to these event, it changes according to event
  • A Bloc is responsible for business logic, It processes event and convert it into state
  • Stream is asynchronous flow of data that UI and Bloc reacts.

Add Bloc architecture to app

We will go step by step to implement architecture :

  1. Add Dependency
  2. Create Repositiory
  3. Add repository dependency
  4. Create BloC
  5. Use BloC
  1. Add Dependency
dependencies:
  flutter_bloc: ^7.0.0

2. Create Repository

├── android
├── ios
├── lib
├── packages
│   └── authentication_repository
└── test

We need to create pubspec.yaml for our new repository

name: authentication_repository
description: Dart package which manages the authentication domain.
publish_to: none

environment:
  sdk: ">=2.12.0-0 <3.0.0"

Now create AuthenticationRepository class file and enum for AuthenticationStatus in lib/src/ in our newly created package

enum AuthenticationStatus{
unknown, authenticated, unauthenticated
}

import 'dart:async';

import 'package:authentication_repository/src/AuthenticationStatus.dart';

class AuthenticationRepository{
  final _controller = StreamController<AuthenticationStatus>();

  Stream<AuthenticationStatus> get status async* {
    await Future<void>.delayed(const Duration(seconds: 1));
    yield AuthenticationStatus.unauthenticated;
    yield* _controller.stream;
  }

  Future<void> login() async{
    await Future<void>.delayed(Duration(seconds: 1), (){
      _controller.add(AuthenticationStatus.authenticated);
    });
  }

  Future<void> logout() async{
    await Future<void>.delayed(Duration(seconds: 1), (){
      _controller.add(AuthenticationStatus.unauthenticated);
    });
  }

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

Next we need to create authentication_repository.dart file which contains public exports

library authentication_repository;

export 'src/AuthenticationRepository.dart';
export 'src/AuthenticationStatus.dart';

We also need UserRepository to display details according to user

├── android
├── ios
├── lib
├── packages
│   ├── authentication_repository
│   └── user_repository
└── test

pubspec.yaml for user_repository

name: user_repository
description: Dart package which manages the user domain.
publish_to: none

environment:
  sdk: ">=2.12.0-0 <3.0.0"

dependencies:
  equatable: ^2.0.0

user model class – we have used Equatable to compare User model (create in lib/src/model)

import 'package:equatable/equatable.dart';

class User extends Equatable {
  const User(this.id);

  final String id;

  @override
  List<Object> get props => [id];

  static const empty = User('-');
}

now we need to create models.dart file in lib/src/model with below content

export 'user.dart';

Now UserRepository with singe method getUser for simplicity, you need to add more as your requirements.

import 'dart:async';
import 'models/models.dart';

class UserRepository {
  User? _user;

  Future<User?> getUser() async {
    if (_user != null) return _user;
    return Future.delayed(
      const Duration(milliseconds: 300),
      () => _user = User("#GeneratedUserId"),
    );
  }
}

now we only need user_repository.dart in lib folder to export our package.

library user_repository;

export 'src/models/models.dart';
export 'src/user_repository.dart';

Add Repository dependency

add following paths in your main pubspec.yaml file under dependencies, be careful about spacing. yaml file is very strict about it. it uses 2 space rule.

authentication_repository:
    path: packages/authentication_repository
user_repository:
    path: packages/user_repository

Don’t forgot to pub get after editing yaml file. Stay tuned with us for part2 of How to implement Bloc architecture in flutter app, Please always use latest version of library whenever you import dependency.