Per kode contoh, data apa pun yang berasal dari Ble_Service tidak memiliki masalah saat merender perubahan di UI melalui penyedia. Tetapi jika saya meneruskan data apa pun dari Ble_Service ke NotifyParser melalui changeParserInput() string json membuatnya berakhir tetapi tidak peduli derai yang saya ikuti, saya tidak bisa membuat UI mengenali keadaan apa pun yang telah berubah dan memperbarui UI di luar seed awal nilai.

Ble_Service -> UI //tidak masalah Ble_Service -> NotifyParserBloc -> UI // Data tidak berhasil.

Mengapa? (kode yang dikomentari berasal dari banyak variasi berbeda yang dicoba)


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;
    });
  }
}

Beri tahu Parser

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");
     });
  }
}
0
nejas 5 Juli 2020, 02:49

1 menjawab

Jawaban Terbaik

Saya tidak tahu apa itu sl<NotifyParserBloc>() tetapi var notifyParser di dalam BleService itu bukan instance yang sama dengan yang Anda buat di Provider (jadi memperbarui/memberi tahu perubahannya sebenarnya tidak memberi tahu yang tergantung di UI). Jika Anda ingin menyimpan instance di penyedia lain, mungkin coba sesuatu seperti ini

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
}

PERBARUI

Anda dapat mencoba melewati Locator yang sama alih-alih Provider.of<NotifyParserBloc>(context, listen: false) agar mudah dibaca

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
}

PERBARUI MENGGUNAKAN GET IT

Jika Anda sudah memiliki instance di getit (sl()) dan ingin mengeksposnya ke penyedia, cukup ubah ChangeNotifierProvider Anda menjadi .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
}

Dengan cara ini, perubahan pada instance di get_it akan memberi tahu UI dari Penyedia

1
EdwynZN 5 Juli 2020, 15:47