Flutter中UDP发送抛出未捕获异常?明明已用try-catch处理
问题根源
模拟器锁屏时UDP发送失败是预期行为,但你用try-catch抓不到SocketException,本质原因是:_RawDatagramSocket.send()虽然是同步方法,但底层Native实现碰到系统权限限制(比如锁屏后系统临时收回网络权限)时,异常会在异步的Isolate消息处理流程里抛出,不在你调用send()的同步代码上下文里,所以外层try-catch根本逮不到它。从报错栈也能看出来,异常最终是在_Timer._runTimers的Isolate消息回调里抛出来的,属于异步任务的未处理异常。
解决办法
1. 监听UDP Socket的错误流
_RawDatagramSocket是Stream类型,直接监听它的错误事件就能捕获底层异常:
// 初始化Socket的时候加上错误监听 _udpSocket!.listen( (event) { // 处理正常的Socket事件,比如接收数据 }, onError: (error) { print("UDP发送失败: $error"); // 这里写你的错误处理逻辑,比如重试、缓存数据包 }, );
2. 用runZonedGuarded兜住所有异步异常
因为你的发送逻辑是在Future.delayed这类异步回调里执行的,用runZonedGuarded可以把整个Zone里的未处理异步异常一网打尽:
runZonedGuarded(() { // 把包含UDP发送的异步逻辑都放在这个Zone里 Future.delayed(Duration(milliseconds: 100), () { try { _udpSocket!.send(_packet, _serverAddress!, Server_UdpPort); } catch (e) { // 这里抓同步抛出的异常,异步的交给下面的回调处理 print("同步异常: $e"); } }); }, (error, stackTrace) { print("捕获到异步未处理异常: $error"); print(stackTrace); });
3. 提前监听锁屏状态,从源头避免异常
直接用插件监听设备锁屏状态,锁屏时暂停发送,解锁后再补发,根本不让错误发生:
// 示例用flutter_screen_state插件,需要先在pubspec里依赖 ScreenState.instance!.addListener((event) { if (event == ScreenStateEvent.SCREEN_OFF) { _isLocked = true; } else if (event == ScreenStateEvent.SCREEN_ON) { _isLocked = false; _sendPendingPackets(); // 补发锁屏期间缓存的数据包 } }); // 发送前先判断锁屏状态 if (!_isLocked) { _udpSocket!.send(_packet, _serverAddress!, Server_UdpPort); } else { _pendingPackets.add(_packet); // 缓存起来等解锁再发 }
额外提醒
send()是同步方法,加await没用,别白费功夫。- 模拟器的权限逻辑和真机可能不一样,建议在真机上测试验证。
内容的提问来源于stack exchange,提问作者Greenlight
相关产品推荐
相关产品推荐

