Listen to Stream and write only once to DB in Flutter

756

Solution 1

I implemented a workaround for this. I assigned the value returned from stream which is scanData to the variable qrData and added to DB if qrData != scanData

void _onQRViewCreated(QRViewController controller) {
    this.controller = controller;

    controller.scannedDataStream.listen((scanData) async {
      if (await canLaunch(scanData)) {
        await launch(scanData);

        if (qrData != scanData) {
          setState(() {
            qrData = scanData;
          });
          final data = QrModel(
            content: scanData,
            date: DateFormat.yMMMd().add_jm().format(DateTime.now()),
          );
          await dbProvider.addData(data);
        }
      } else {
        if (!alertBoxOpen) {
          if (qrData != scanData) {
            setState(() {
              qrData = scanData;
            });
            final data = QrModel(
              content: scanData,
              date: DateFormat.yMMMd().add_jm().format(DateTime.now()),
            );
            await dbProvider.addData(data);
          }

          setState(() => alertBoxOpen = true);

          showDialog(
              context: context,
              builder: (context) {
                return AlertDialog(
                  content: Text(qrData),
                  actions: [
                    MaterialButton(
                        child: Text('OK',
                            style: TextStyle(
                                fontSize: 18.0, fontWeight: FontWeight.bold)),
                        onPressed: () {
                          setState(() => alertBoxOpen = false);
                          Navigator.of(context).pop();
                        }),
                  ],
                );
              });
        }
      }
    });
  }

Solution 2

Do you have a single subscription on stream or is it that the stream emits multiple same values? If it is the latter I suggest you try rxdart package. It is an implementation of ReactiveX for Dart. I am not that much experienced in reactive programming, but in my experience when I used BehaviorSubject from rxdart it didn't notify subscribers when the same value was added to it. So one thing you could do is to add each value from the QR Stream to BehaviorSubject, and instead subscribe (listen) to behavior subject for making queries to database.

Share:
756
Dulanka
Author by

Dulanka

An individual interested in mastering technological skills and learning new tech trends.

Updated on December 26, 2022

Comments

  • Dulanka
    Dulanka over 1 year

    I'm developing a QR code reader app and I use an external QR reader package (https://pub.dev/packages/qr_code_scanner). It listens to a Stream and returns QR data. But when I write the data to sqlite database it writes the same data several times because it doesn't stop listening to Stream. I dont think unsubscribing from stream is a good idea because i still need the stream to listen after coming back from a url launch or closing the dialog. Please correct me if I'm wrong and suggest a solution, Thank You.

    void _onQRViewCreated(QRViewController controller) {
        this.controller = controller;
        controller.scannedDataStream.listen((scanData) async {
          
          setState(() {
            qrData = scanData;
          });
      
          if (await canLaunch(qrData)) {
            var status = await launch(qrData);
    
            if(status){
              final data = QrModel(
                content: scanData,
                date: DateFormat.yMMMd().add_jm().format(DateTime.now()),
              );
              await dbProvider.addData(data);
            }
    
          } else {
    
            if (!alertBoxOpen) {
    
              final data = QrModel(
                content: scanData,
                date: DateFormat.yMMMd().add_jm().format(DateTime.now()),
              );
              await dbProvider.addData(data);
    
              setState(() => alertBoxOpen = true);
              
              showDialog(
                  context: context,
                  builder: (context) {
                    return AlertDialog(
                      content: Text(qrData),
                      actions: [
                        MaterialButton(
                            child: Text('OK',
                                style: TextStyle(
                                    fontSize: 18.0, fontWeight: FontWeight.bold)),
                            onPressed: () {
                              setState(() => alertBoxOpen = false);
                              Navigator.of(context).pop();
                            }),
                      ],
                    );
                  });
            }
          }
        });
        
      }