Flutter:如何暂停和重新启动“Stream”侦听器?
Posted
技术标签:
【中文标题】Flutter:如何暂停和重新启动“Stream”侦听器?【英文标题】:Flutter: How to pause and restart a `Stream` listener? 【发布时间】:2021-06-08 10:55:58 【问题描述】:我正在开发一个 Flutter 应用程序来读取 QR 码。我正在使用qr_code_scanner: ^0.3.5
库。下面是我的代码。
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:qr_code_scanner/qr_code_scanner.dart';
class ScanQRCodeScreen extends StatelessWidget
@override
Widget build(BuildContext context)
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
title: Text("Scan QR Code"),
),
body: _ScanQRCodeUI());
class _ScanQRCodeUI extends StatefulWidget
@override
State<StatefulWidget> createState()
return _ScanQRCodeUIState();
class _ScanQRCodeUIState extends State<_ScanQRCodeUI>
final GlobalKey qrKey = GlobalKey(debugLabel: 'QR');
Barcode result;
QRViewController controller;
// In order to get hot reload to work we need to pause the camera if the platform
// is android, or resume the camera if the platform is ios.
@override
void reassemble()
super.reassemble();
if (Platform.isAndroid)
controller.pauseCamera();
else if (Platform.isIOS)
controller.resumeCamera();
@override
Widget build(BuildContext context)
return Column(
children: [
Expanded(flex: 4, child: _buildQrView(context)),
Expanded(flex: 1, child: _dataDisplayUI())
],
);
Widget _buildQrView(BuildContext context)
// For this example we check how width or tall the device is and change the scanArea and overlay accordingly.
var scanArea = (MediaQuery.of(context).size.width < 400 ||
MediaQuery.of(context).size.height < 400)
? 200.0
: 400.0;
// To ensure the Scanner view is properly sizes after rotation
// we need to listen for Flutter SizeChanged notification and update controller
return QRView(
key: qrKey,
onQRViewCreated: _onQRViewCreated,
overlay: QrScannerOverlayShape(
borderColor: Colors.red,
borderRadius: 10,
borderLength: 30,
borderWidth: 10,
cutOutSize: scanArea),
);
void _onQRViewCreated(QRViewController controller)
setState(()
this.controller = controller;
);
controller.scannedDataStream.listen((scanData) async
print("Hello0");
setState(()
result = scanData;
print(result.code);
);
// await controller.pauseCamera();
);
Widget _dataDisplayUI()
const yellowColor = const Color(0xffEDE132);
return Column(
children: [
Row(
children: [
Expanded(
flex: 7,
child: Container(
margin:
EdgeInsets.only(top: 30, bottom: 30, left: 10, right: 10),
child:
Text("You have added 12 products. Click here to publish.",
style: GoogleFonts.poppins(
textStyle: TextStyle(
color: Colors.black,
fontWeight: FontWeight.normal,
fontSize: 14,
))),
)),
Expanded(
flex: 3,
child: Container(
width: 60,
height: 60,
child: Center(
child: Text("12",
style: GoogleFonts.poppins(
textStyle: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 21,
)))),
decoration:
BoxDecoration(shape: BoxShape.circle, color: yellowColor),
))
],
)
],
);
@override
void dispose()
controller?.dispose();
super.dispose();
我正在使用这个应用程序逐个扫描产品,就像收银员使用条形码扫描仪在超级标记中所做的那样。
问题是,这个扫描器正在监听 stream
并且它一直在运行。请注意_onQRViewCreated
方法。因此,在我们将相机移至下一个二维码之前,同一个二维码已被多次读取。
如何确保两次扫描之间存在延迟?例如,当我扫描一个二维码时,我必须再等待 2 秒才能扫描下一个二维码。
如果我在两次扫描之间创建延迟的想法是错误的,我也愿意接受其他想法。
【问题讨论】:
【参考方案1】:你可以使用
controller.scannedDataStream.first
停止监听流中的其他事件。
另一种解决方案是设置如下内部状态属性:
bool QrBeingProcessed = false;
当您扫描第一个 qr 时,将其设置为 true,直到您完成。
【讨论】:
【参考方案2】:另一种方法是使用 DateTime 来检查当前扫描与上次扫描之间的时间差是否低于指定量(例如 3 秒)。如果是这样,我们不会将状态设置为新的 scanData。实际上,这会在每次 QR 码扫描之间产生 3 秒的延迟。请参阅下面的代码。
controller.scannedDataStream.listen((scanData)
final currentScan = DateTime.now();
if (lastScan == null || currentScan.difference(lastScan!) > const Duration(seconds: 3))
lastScan = currentScan;
print(scanData.code);
setState(()
result = scanData;
print('the qr just read was ' + scanData.code);
);
);
【讨论】:
以上是关于Flutter:如何暂停和重新启动“Stream”侦听器?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 jquery transit 中暂停和重新启动 css3 转换
如何在应用重新启动之间保存和恢复 Flutter ListView 的滚动位置?