在 Flutter 中监听 Stream 只写一次到 DB
Listen to Stream and write only once to DB in Flutter
我正在开发一个 QR 码 reader 应用程序,我使用外部 QR reader 包 (https://pub.dev/packages/qr_code_scanner)。
它监听 Stream 和 returns 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();
}),
],
);
});
}
}
});
}
您是否在流上有一个订阅,或者流是否发出多个相同的值?如果是后者我建议你试试 rxdart 包。它是 ReactiveX for Dart 的一个实现。我在反应式编程方面经验不多,但根据我的经验,当我使用 rxdart 中的 BehaviorSubject
时,当向其添加相同的值时,它不会通知订阅者。因此,您可以做的一件事是将 QR 流中的每个值添加到 BehaviorSubject
,而不是订阅(收听)行为主题以查询数据库。
我为此实施了一个解决方法。我将从流返回的值 scanData
分配给变量 qrData
并在 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();
}),
],
);
});
}
}
});
}
我正在开发一个 QR 码 reader 应用程序,我使用外部 QR reader 包 (https://pub.dev/packages/qr_code_scanner)。 它监听 Stream 和 returns 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();
}),
],
);
});
}
}
});
}
您是否在流上有一个订阅,或者流是否发出多个相同的值?如果是后者我建议你试试 rxdart 包。它是 ReactiveX for Dart 的一个实现。我在反应式编程方面经验不多,但根据我的经验,当我使用 rxdart 中的 BehaviorSubject
时,当向其添加相同的值时,它不会通知订阅者。因此,您可以做的一件事是将 QR 流中的每个值添加到 BehaviorSubject
,而不是订阅(收听)行为主题以查询数据库。
我为此实施了一个解决方法。我将从流返回的值 scanData
分配给变量 qrData
并在 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();
}),
],
);
});
}
}
});
}