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

795 Views Asked by At

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')),
          );
  }
}
1

There are 1 best solutions below

2
On BEST ANSWER

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.