Почему никакие изменения из NotifyParser не отображаются в пользовательском интерфейсе с помощью Provider / ChangeNotifier / Streambuilder, но будут из класса обслуживания
Согласно примеру кода, любые данные, поступающие из Ble_Service, не имеют проблем с отображением изменений в пользовательском интерфейсе через провайдера. Но если я передаю какие-либо из этих данных из Ble_Service в NotifyParser через changeParserInput(), строка json сделает это, но независимо от того, за чем я следую, я не могу заставить пользовательский интерфейс распознавать какое-либо изменение состояния и обновлять пользовательский интерфейс за пределами начального семени. значение.
Ble_Service -> UI // нет проблем Ble_Service -> NotifyParserBloc -> UI // Данные не справляются.
Зачем? (закомментированный код взят из множества опробованных вариантов)
import 'package:flutter/material.dart';
import 'package:flutter_app_belt_provider/blocs/notifyParser_bloc.dart';
import 'package:flutter_app_belt_provider/services/bleBelt_service.dart';
import 'package:flutter_app_belt_provider/services/service_locator.dart';
import 'package:provider/provider.dart';
void main() {
setupServiceLocator(); // <-- get it service locator function
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (context) => BleService()),
ChangeNotifierProvider(create: (context) => NotifyParserBloc()),
//StreamProvider.value(value: NotifyParserBloc().parserInput)
],
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
//final NotifyParserBloc _notify = NotifyParserBloc();
@override
Widget build(BuildContext context) {
var _service = Provider.of<BleService>(context);
//var _bloc = Provider.of<NotifyParserBloc>(context, listen: false);
return Scaffold(
appBar: AppBar(
title: Text("poo"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
child: FlatButton(
child: Text(
"Scan",
),
onPressed: () {
_service.startScan();
},
)
),
Container(
child: FlatButton(
child: Text(
"Connect",
),
onPressed: () {
_service.connectToDevice();
},
)
),
Container(
child: FlatButton(
child: Text(
"Services",
),
onPressed: () {
_service.discoverServices();
},
)
),
Container(
child: FlatButton(
child: Text(
"Disconnect",
),
onPressed: () {
_service.disconnectFromDevice();
},
)
),
Consumer<NotifyParserBloc>(
builder: (context, notifyParserBloc, child) => Text(notifyParserBloc.parserInput)
),
Consumer<BleService>(
builder: (context, bleService, child) => Text(bleService.viaService)
),
StreamBuilder<String>(
initialData: "0",
stream: Provider.of<NotifyParserBloc>(context, listen: false).parserInputStream,
builder: (context, snapshot) {
if(snapshot.data == null) return CircularProgressIndicator();
else return Text(
snapshot.data.toString(),
style: TextStyle(fontSize: 14.0, color: Colors.black),
textAlign: TextAlign.center,
);}
),
// StreamProvider<String>.value(
// initialData: "go",
// value: _bloc.parserInput,
// child: ValueWidget(),
// ),
],
),
),
);
}
}
class ValueWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
//var model = Provider.of<NotifyParserBloc>(context);
return Column(
children: <Widget>[
Text('Listening a value :' + Provider.of<String>(context).toString(),),
],
);
}
}
ble_service
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter_app_belt_provider/services/service_locator.dart';
import 'package:flutter_blue/flutter_blue.dart';
import 'dart:convert' show utf8;
import 'package:rxdart/rxdart.dart';
import 'package:flutter_app_belt_provider/blocs/notifyParser_bloc.dart';
class BleService with ChangeNotifier {
//NotifyParserBloc _bloc = NotifyParserBloc();
var notifyParser = sl<NotifyParserBloc>();
//class BleService{
final String TARGET_DEVICE_NAME = "ESP32";
final String SERVICE_UUID = "4fafc201-1fb5-459e-8fcc-c5c9c331914b";
final String NOTIFY_UUID = "beb5483e-36e1-4688-b7f5-ea07361b26a8";
final String WRITE_UUID = "724b0547-3747-4c00-9710-5305a020018f";
FlutterBlue flutterBlue = FlutterBlue.instance;
StreamSubscription<ScanResult> scanSubScription;
BluetoothDevice beltDevice;
BluetoothCharacteristic characteristicNotify;
BluetoothCharacteristic characteristicWrite;
String bleNotifyString = "";
//BleBeltNotifyParserBloc _bloc = BleBeltNotifyParserBloc();
BehaviorSubject<String> _bleStatusFromBeltController = BehaviorSubject<String>.seeded("Disconnected");
Stream<String> get bleStatusFromBelt => _bleStatusFromBeltController.stream;
StreamController<String> _bleNotifyFromBeltController = BehaviorSubject<String>.seeded("BLE NOTIFY");
Stream<String> get bleNotifyFromBelt => _bleNotifyFromBeltController.stream;
Sink<String> get bleNotifyFromBeltSink => _bleNotifyFromBeltController.sink;
BehaviorSubject<String> _bleButtonTextController = BehaviorSubject<String>.seeded("button text");
Stream<String> get bleButtonTextGet => _bleButtonTextController.stream;
//BleService();
dispose() {
_bleStatusFromBeltController.close();
_bleNotifyFromBeltController.close();
}
startScan() {
stopScan();
// // SCANNING
scanSubScription = flutterBlue.scan().listen((scanResult) async {
if (scanResult.device.name == TARGET_DEVICE_NAME) {
stopScan();
// // FOUND
beltDevice = scanResult.device;
_bleStatusFromBeltController.add("Found");
//connectToDevice();
}
}, onDone: () => stopScan());
}
stopScan() {
flutterBlue.stopScan();
scanSubScription?.cancel();
scanSubScription = null;
_bleStatusFromBeltController.add("Disconnected");
print("print Disconnected");
}
connectToDevice() async {
if (beltDevice == null) return;
// CONNECTING
await beltDevice.connect();
beltDevice.requestMtu(185);
print('print DEVICE CONNECTED');
print(" print BeltDevice $beltDevice");
_bleStatusFromBeltController.add("Connected");
print("print Connected");
//discoverServices();
}
discoverServices() async {
print("discoverServices beltDevice name is $beltDevice");
if (beltDevice == null) return;
List<BluetoothService> services = await beltDevice.discoverServices();
services.forEach((service) {
// do something with service
if (service.uuid.toString() == SERVICE_UUID) {
service.characteristics.forEach((characteristic) {
// set up notify characteristic
print("Service Found for $characteristic");
if (characteristic.uuid.toString() == NOTIFY_UUID) {
characteristicNotify = characteristic;
// tell characteristic on server to notify
characteristicNotify.setNotifyValue(true);
print("notify set to true");
// listen, convert and put notify value in stream
characteristicNotify.value.listen((value) {
bleNotifyString = utf8.decode(value);
//print("got characteristic $value");
print(bleNotifyString);
notifyParser.changeParserInput(bleNotifyString);
print("print Transmitting");
viaServiceChangeParserInput(bleNotifyString);
//_bleNotifyFromBeltController.sink.add(bleNotifyString);
//_bloc.parserInputSink.add(bleNotifyString);
//_bleStatusFromBeltController.add("Transmitting");
});
// COMMUNICATING
}
// Prepares characteristic for Write
if (characteristic.uuid.toString() == WRITE_UUID) {
characteristicWrite = characteristic;
}
});
}
});
}
String _viaServiceChangeParserInput = "via Service";
String get viaService => _viaServiceChangeParserInput;
viaServiceChangeParserInput(String value) {
_viaServiceChangeParserInput = value;
print("via Service $_viaServiceChangeParserInput");
notifyListeners();
}
disconnectFromDevice() {
beltDevice.disconnect();
_bleStatusFromBeltController.add("Disconnected");
print("Disconnected");
// DISCONNECTED
}
bleButtonText() async {
_bleStatusFromBeltController.listen((String data) {
String buttonText;
if (data == "Disconnected") buttonText = "SCAN";
else if (data == "Found") buttonText = "CONNECT";
else if (data == "Connected") buttonText = "DISCONNECT";
return buttonText;
});
}
}
Уведомить парсер
import 'package:flutter/foundation.dart';
import 'package:flutter_app_belt_provider/services/bleBelt_service.dart';
import 'dart:async';
import 'package:rxdart/rxdart.dart';
class NotifyParserBloc with ChangeNotifier{
// NotifyParserBloc({@required this.bleService});
// final BleService bleService;
//final BleService bleService;
StreamController<String> _notifyParserController = BehaviorSubject<String>.seeded("parseNotify");
Stream<String> get parserInputStream => _notifyParserController.stream;
//
// Future<void> parseNotify(String data) async {
// _notifyParserController.add(data);
// print("PARSENOTIFYBLOC: $data");
// _notifyParserController.stream.listen((event) {
// print("NOTIFYPARSERSTREAM: $event");
// });
// }
String _parserInput;
NotifyParserBloc(){
_parserInput = "let's get this started";
}
String get parserInput => _parserInput;
void changeParserInput(String value) {
_parserInput = value;
notifyListeners();
print("change parser value $_parserInput");
_notifyParserController.add(value);
_notifyParserController.stream.listen((event) {
print("NOTIFYPARSERSTREAM: $event");
});
}
}
1 ответ
Я не знаю что это sl<NotifyParserBloc>()
но var notifyParser внутри BleService это не тот экземпляр, который вы создали в Provider (поэтому обновление / уведомление об изменениях в нем фактически не уведомляет тот, который зависит от пользовательского интерфейса). Если вы хотите сохранить экземпляр в другом провайдере, возможно, попробуйте что-то вроде этого
MultiProvider(
providers: [
ChangeNotifierProvider(create: (context) => NotifyParserBloc()),
ChangeNotifierProvider(create: (context) => BleService(Provider.of<NotifyParserBloc>(context, listen: false)),
],
child: MyApp(),
),
class BleService with ChangeNotifier {
final notifyParser;
BleService(this.notifyParser); //save the instance in the constructor
...
notifyParser.changeParserInput(bleNotifyString); //now it will update the one using the UI
}
ОБНОВИТЬ
Вы можете попробовать такую же передачу Локатора вместо Provider.of<NotifyParserBloc>(context, listen: false)
для удобочитаемости
MultiProvider(
providers: [
ChangeNotifierProvider(create: (context) => NotifyParserBloc()),
ChangeNotifierProvider(create: (context) => BleService(context.read)), //this is an extension method that allows us to use the Locator
],
child: MyApp(),
),
class BleService with ChangeNotifier {
final notifyParser;
BleService(Locator locator) : notifyParser = locator<NotifyParserBloc>(); //save the instance in the constructor
...
notifyParser.changeParserInput(bleNotifyString); //now it will update the one using the UI
}
ОБНОВЛЕНИЕ ПОЛУЧИТЬ
Если у вас уже был экземпляр в getit (sl()) и вы хотите предоставить его поставщику, просто измените свой ChangeNotifierProvider на.value
MultiProvider(
providers: [
ChangeNotifierProvider.value(value: sl<NotifyParserBloc>()), //this will expose the same instance of the get it to the UI
ChangeNotifierProvider(create: (context) => BleService())
],
child: MyApp(),
),
class BleService with ChangeNotifier {
var notifyParser = sl<NotifyParserBloc>();
// No need for the constructor now
...
notifyParser.changeParserInput(bleNotifyString); //now it will update the one using the UI
}
Таким образом, изменения в экземпляре в get_it будут уведомлять пользовательский интерфейс от поставщика