'How can I update my get function when stream changes state?

I am using flutter_blue_plus for getting bluetooth is on or off. I am getting results in log successfully. But in isOn function, I can't update automatically. What can I do? Do I have to use StreamBuilder in UI?

class BluetoothService with Logger {
  BluetoothService() {
    log.fine('listening to bluetooth status changes');

    FlutterBluePlus.instance.state.listen((result) {
      log.fine('bluetooth state changed to ${result.name}');
      _lastResult = result;
    });
  }
  BluetoothState _lastResult = BluetoothState.unknown;

  /// The last [BluetoothState] that is updated automatically whenever the
  /// state changes.

  bool get isOn => _lastResult == BluetoothState.on;

  Future<void> initialize() async {
    try {
      await FlutterBluePlus.instance.isAvailable;
    } catch (e, st) {
      log.warning('unable to initialize bluetooth', e, st);
    }
  }
}
        

class BluetoothDeviceList extends StatelessWidget {
  const BluetoothDeviceList({Key? key}) : super(key: key);
  static const route = 'bluetoothdevicelist';

  @override
  Widget build(BuildContext context) {
    return app<BluetoothService>().isOn
        ? Scaffold(
            body: Center(child: Text('DEVICES')),
          )
        : Scaffold(
            body: Center(child: Text('Bluetooth Close')),
          );
  }
}


Solution 1:[1]

This is definitely a situation where you need to use some state management approach. In our team we use flutter_bloc, in which case your solution would look something like this.

class BluetoothCubit extends Cubit<BluetoothState> with Logger {
  BluetoothCubit() : super(BluetoothState.unknown) {
    log.fine('listening to bluetooth status changes');

    FlutterBluePlus.instance.state.listen((result) {
      log.fine('bluetooth state changed to ${result.name}');
      emit(result);
    });
  }

  Future<void> initialize() async {
    try {
      await FlutterBluePlus.instance.isAvailable;
    } catch (e, st) {
      log.warning('unable to initialize bluetooth', e, st);
    }
  }
}

class BluetoothDeviceList extends StatelessWidget {
  static const route = 'bluetoothdevicelist';

  const BluetoothDeviceList({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) => BlocProvider(
        create: (_) => BluetoothCubit()..initialize(),
        child: BlocBuilder<BluetoothCubit, BluetoothState>(
          builder: (context, state) => Scaffold(
            body: Center(
              child: Text(
                state == BluetoothState.on ? 'DEVICES' : 'Bluetooth Close',
              ),
            ),
          ),
        ),
      );
}

One of the key changes is that in your stream listener you call emit(result). This informs the BlocBuilder that a new state needs to be displayed.

There are other ways to handle this, but this is the standard approach in our company.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Guy Kogus