5

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();
                        }),
                  ],
                );
              });
        }
      }
    });
    
  }
Dulanka
  • 139
  • 9

2 Answers2

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.

Dharman
  • 30,962
  • 25
  • 85
  • 135
rasuru
  • 273
  • 1
  • 10
  • Since I'm not familiar with rxdart, can you please elaborate more on how to implement this solution? – Dulanka Dec 14 '20 at 17:57
  • 1
    @Dulanka After going through rxdart docs I found the `distinct` method [here](https://pub.dev/documentation/rxdart/latest/rx/BehaviorSubject/distinct.html). It's implementation uses `distinct` method of Dart's Stream. So, you probably don't need rxdart. Just call `.distinct()` on the stream before you listen to it. But this will work only if the stream emits multiple same values. Not if there are multiple subscriptions – rasuru Dec 15 '20 at 06:41
  • Thanks for your effort! This function is really helpful. But the user cannot scan the same QR again because the stream won't allow equal values. – Dulanka Dec 15 '20 at 14:10
  • @Dulanka The user should be able to scan the same QR code after scanning a different QR code. After all, you said you don't want same event to happen twice or more in a row. Are you sure you are subscribing only once? – rasuru Dec 15 '20 at 20:59
0

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();
                        }),
                  ],
                );
              });
        }
      }
    });
  }
Dulanka
  • 139
  • 9