hopefully I can make myself clear.

After video and tutorials, I found this way to have some widgets to input data to the bloc (valueSetting) and some others to get this data (value).

What I am asking is if there is a better way (there has to be..). I want to avoid the need to have 4 variables for just 1 real value shared between widgets.

import 'dart:async';

import 'package:rxdart/subjects.dart';

class BlocExample {
  final _valueSettingController = StreamController<bool>();

  // object use by widget to push data
  Sink<bool> get valueSetting => _valueSettingController.sink;

  final _value = BehaviorSubject<bool>(seedValue: false);

  // object used by widget to get data
  Stream<bool> get value => _value.stream;

  BlocExample() {
    _valueSettingController.stream.listen(_value.add);
  }

  void dispose() {
    _value.close();
    _valueSettingController.close();
  }
}


Solution 1: diegoveloper

You can do something like this :)

  enum STREAM_GROUP {
    TYPE1,TYPE2,TYPE3
  }

  class BlocExample {

        Map<STREAM_GROUP, StreamController<bool>> groups = new Map();

        Stream<bool> getValue(STREAM_GROUP type){
          return groups[type].stream;
        }
        Sink<bool> getValueSetting(STREAM_GROUP type){
          return groups[type].sink;
        }

        BlocExample() {
          groups[STREAM_GROUP.TYPE1] = StreamController<bool>();
          groups[STREAM_GROUP.TYPE2] = StreamController<bool>();
          groups[STREAM_GROUP.TYPE3] = StreamController<bool>();

          groups.forEach((groupType, streamController){
              final currentValue = BehaviorSubject<bool>(seedValue: false);
              streamController.stream.listen(currentValue.add);
          });

        }

        void dispose() {
           groups.forEach((groupType, streamController){
              streamController.close();
          });
        }
      }


Solution 2: Rémi Rousselet

First of, let me say that you can remove the private variables by using a custom factory constructor. Here's an example:

class MyBloc {
  final Sink<bool> input;
  final Stream<bool> output;
  final VoidCallback _dispose;

  MyBloc._({this.input, this.output, VoidCallback dispose}) : _dispose = dispose;

  factory MyBloc() {
    final mainController = BehaviorSubject(seedValue: false);
    return MyBloc._(
      input: mainController.sink,
      output: mainController.stream,
      dispose: () {
        mainController.close();
      },
    );
  }

  void dispose() {
    _dispose();
  }
}

Secondly, the problem you're trying to solve is actually not a problem. While it seems at first that there's a lot of duplicates; in reality they serve different purposes.

In many situations, your Stream will be more than just _controller.stream. For example, for whatever reason you may want to transform the value before exposing it:

final mainController = BehaviorSubject(seedValue: false);

final Stream<bool> output = mainController.map((foo) => !foo);

This code makes that the output stream reverses the value of everything passed to mainController.sink

But in my situation this is not the case. So why 3 variables that point to the same thing?

The fact that in your situation, your controller is both the sink and stream without transformation is an implementation detail and may be subject to changes.

By exposing Sink/Stream as done before, you actually abstract this implementation detail. So that in the future if your stream needs custom operations; no change will be required by your UI.

This is not necessary. But recommended.