在 Flutter 中监听 Stream 并只向 DB 写入一次
Posted
技术标签:
【中文标题】在 Flutter 中监听 Stream 并只向 DB 写入一次【英文标题】:Listen to Stream and write only once to DB in Flutter 【发布时间】:2020-12-12 12:54:39 【问题描述】:我正在开发一个 QR 码阅读器应用程序并使用外部 QR 阅读器包 (https://pub.dev/packages/qr_code_scanner)。 它侦听 Stream 并返回 QR 数据。但是当我将数据写入 sqlite 数据库时,它会多次写入相同的数据,因为它不会停止监听 Stream。我不认为从流中取消订阅是一个好主意,因为在从 url 启动或关闭对话框返回后,我仍然需要流来收听。如果我错了,请纠正我并提出解决方案,谢谢。
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();
),
],
);
);
);
【问题讨论】:
【参考方案1】:您在流上是否有一个订阅,还是流发出多个相同的值?如果是后者我建议你试试rxdart 包。它是 Dart 的 ReactiveX 实现。我在反应式编程方面没有太多经验,但是根据我的经验,当我使用 rxdart 中的BehaviorSubject
时,它不会在添加相同的值时通知订阅者。因此,您可以做的一件事是将 QR 流中的每个值添加到 BehaviorSubject
,然后订阅(收听)行为主题以查询数据库。
【讨论】:
由于我对 rxdart 不熟悉,能否请您详细说明如何实现此解决方案? @Dulanka 在浏览 rxdart 文档后,我发现了distinct
方法 here。它的实现使用了 Dart 的 Stream 的 distinct
方法。所以,你可能不需要 rxdart。在收听之前,只需在流中致电.distinct()
。但这仅在流发出多个相同值时才有效。如果有多个订阅,则不会
感谢您的努力!这个功能真的很有帮助。但用户无法再次扫描相同的 QR,因为流不允许相同的值。
@Dulanka 用户在扫描不同的二维码后应该能够扫描相同的二维码。毕竟,您说过您不希望同一事件连续发生两次或多次。你确定你只订阅一次吗?【参考方案2】:
我为此实施了一个解决方法。我将从流返回的值 scanData
分配给变量 qrData
并添加到 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();
),
],
);
);
);
【讨论】:
以上是关于在 Flutter 中监听 Stream 并只向 DB 写入一次的主要内容,如果未能解决你的问题,请参考以下文章
Flutter:在 Stream 类中访问 SharedPreferences Provider / ChangeNotifier