How to use Flutter BLoC pattern on specific scenarios?

Issue

Recently I am start to learn Flutter and its BLoC partten, and there are many class in BLoC library, like Bloc, PublishSubject, StreamController, BehaviorSubject and etc..

My question is, what the scenarios that I can use these classes? For example, I can inherited from bloc or not inherited from it, but why? I am confuse for that, What’s the usage scenarios for those classes?

Solution

As you can see, there are more than one ways to implement Bloc in your apps. The class you mentioned above are in fact from different packages: PublishSubject and BehaviorSubject are from rxdart package while StreamController is within the Flutter SDK package dart:async

However, you are not required to use all or even any of them to implement Bloc in your Flutter apps. I’ll make an example by implement Bloc without using any package:

1. Implement Bloc the vanilla way:
You can implement Bloc using what’s in Flutter SDK without using other package. Usually you create a bloc class separating your logic from the UI. The class might look like this:

import 'dart:async';

// This is the class that handle all the logic such as receiving data from API, process those data, etc (I'll call it a data processing unit)
class YourBloc {
  
  // Create a stream to send processed data to the UI
  final StreamController _someController = StreamController();

  Stream get someStream => _someController.stream;

  // Get the data from API, then send the data to stream here. Usually an async function
  void loadData() async {
    final data = await doYourApiCall(); // Get data from API
    var processedData = processYourData(data);
    _someController.add(processedData);
  }

  dispose() {
    _someController.close();
  }
}

Meanwhile in the UI, you initiate the loadData() and listen to the response data with StreamBuilder:

class _SomeScreenState extends State<SomeScreen> {
  // Initiate your bloc
  final YourBloc _bloc = YourBloc();

  // Make the loadData() call
  @override
  void initState() {
    _bloc.loadData();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return StreamBuilder( // Listen to the datastream with StreamBuilder
      stream: _bloc.someStream,
      builder: (context, snapshot) {
        if (!snapshot.hasData)
          return Center(child: CircularProgressIndicator());
        return ListView.builder(
          itemCount: snapshot.data.length,
          itemBuilder: (context, index) => _buildYourItem(index),
        );
      },
    );
  }
}

2. So what’s the packages are for
There are some packages you can make use of to implement Bloc such as flutter_bloc or rxdart. flutter_bloc provides a way to structure your bloc consistenly using Bloc/Event/State concepts, rx_dart provides many tools so you can manipulate the Stream to your own need. You might see people mentioned provider as well, it’s main purpose is to pass an object down the widget tree and create a data flow through out your app.

Each is already pretty mature and implemented by many programmers. I recommend going into the documentations of each one of them only after you implement Bloc the vanilla way so you can actually understand what they’re doing behind the scenes.

Answered By – Bach

Answer Checked By – Mary Flores (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *