I have the following setup:
App with multiple pages: VoltagesPage
& TemperaturesPage
I will receive some data over bluetooth serial like so:
bluetooth_data_provider.dart
import 'dart:convert';
import 'dart:typed_data';
import 'package:flutter/widgets.dart';
import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart';
class BluetoothDataProvider with ChangeNotifier {
String _data = '';
String get data => _data;
String _messageBuffer = '';
BluetoothConnection? _connection;
connectAndListen(String address) {
BluetoothConnection.toAddress(address).then((connection) {
print('Connected to the device');
_connection = connection;
if (_connection == null) {
return;
}
_connection!.input!.listen(_onDataReceived).onDone(() {});
}).catchError((error) {
print('Cannot connect, exception occured');
print(error);
});
}
void _onDataReceived(Uint8List data) {
String dataStr = ascii.decode(data);
_messageBuffer += dataStr;
if (dataStr.contains('\n')) {
print(_messageBuffer);
_data = _messageBuffer.substring(0, _messageBuffer.length - 1);
_messageBuffer = '';
notifyListeners();
}
}
}
This will notify all listeners, that listen to BluetoothDataProvider
's changes to its data
field.
Now the TemperaturesPage
is not really interested in a message, that is meant for the VoltagesPage
and vice versa. I can identify who should receive the message by a prefix that is being sent by the device.
A voltage message can look like this:
V:+12.5
A temperature message can look like this:
T:+45.6
Right now when I'm watching the BluetoothDataProvider
, from both of the pages, the widget has to decide whether to accept the message, or not. But this might leave a widget hanging, because it still needs to rebuild the widget as build
is being called.
What I really want is something like this:
import 'dart:convert';
import 'dart:typed_data';
import 'package:flutter/widgets.dart';
import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart';
class BluetoothDataProvider with ChangeNotifier {
String _data = '';
String get data => _data;
String _messageBuffer = '';
BluetoothConnection? _connection;
connectAndListen(String address) {
BluetoothConnection.toAddress(address).then((connection) {
print('Connected to the device');
_connection = connection;
if (_connection == null) {
return;
}
_connection!.input!.listen(_onDataReceived).onDone(() {});
}).catchError((error) {
print('Cannot connect, exception occured');
print(error);
});
}
void _onDataReceived(Uint8List data) {
String dataStr = ascii.decode(data);
_messageBuffer += dataStr;
if (dataStr.contains('\n')) {
print(_messageBuffer);
_data = _messageBuffer.substring(0, _messageBuffer.length - 1);
_messageBuffer = '';
if(_data.startsWith("T:")) {
// notify with a TemperatureProvider
} else if (_data.startsWith("V:")){
// notify with a VoltageProvider
}
}
}
}
That way, each page could listen to a different Provider and only receive data they are actually interested in.
Is a scenario like this possible?
Thanks!
I solved this now.
In my main.dart, I will just create an instance of BluetoothDataProvider
in initState()
and providing the context from there to the constructor of BluetoothDataProvider
.
After that, I am free to use the context to call different providers as follows:
void _onDataReceived(Uint8List data) {
String dataStr = ascii.decode(data);
_messageBuffer += dataStr;
if (dataStr.contains('\n')) {
print(_messageBuffer); // here you get complete string
_data = _messageBuffer.substring(0, _messageBuffer.length - 1);
_messageBuffer = ''; //clear buffer to accept new string
var messageType = _data.substring(0, 2);
switch (messageType) {
case "V:":
context.read<CurrentReceivedMessage>().setMessage(_data);
break;
case "T:":
context.read<TemperatureReceivedMessage>().setMessage(_data);
break;
}
}
}