无法捕获异步异常

Cannot catch an asynchronous exception

这是我的问题的一个简单示例:

import 'dart:async';

void main() {
  try {
    Timer(Duration(seconds: 1), () {
      throw TimeoutException('1 second has expired');
    });
  } catch (o) {
    print("caught ${o.runtimeType}");
  }
}

我想问题是计时器在 try-catch 块终止后完成倒计时,考虑到倒计时是异步的并且初始化 Timer 成功。如何在不更改 Timer?

的回调函数的情况下捕获异常

在我的具体情况下,我使用 flutter_blue 并且在使用异步方法 BluetoothDevice#connect() 时遇到问题。

/// Establishes a connection to the Bluetooth Device.
Future<void> connect({
  Duration? timeout,
  bool autoConnect = true,
}) async {
  var request = protos.ConnectRequest.create()
    ..remoteId = id.toString()
    ..androidAutoConnect = autoConnect;

  Timer? timer;
  if (timeout != null) {
    timer = Timer(timeout, () {
      disconnect();
      throw TimeoutException('Failed to connect in time.', timeout);
    });
  }

  await FlutterBlue.instance._channel
      .invokeMethod('connect', request.writeToBuffer());

  await state.firstWhere((s) => s == BluetoothDeviceState.connected);

  timer?.cancel();

  return;
}

我这样调用方法:

try {
  await (device as BluetoothDevice).connect(timeout: Duration(seconds: 1));
} catch (o) {
  print("caught ${o.runtimeType}");
}

考虑到我用 await 等待 BluetoothDevice#connect() 并且在用 timer?.cancel(); 成功连接(在方法结束时)后计时器被取消,我不知道为什么要尝试-catch 未捕获以下 TimeoutException:

E/flutter ( 3710): [ERROR:flutter/lib/ui/ui_dart_state.cc(199)] Unhandled Exception: TimeoutException after 0:00:01.000000: Failed to connect in time.
E/flutter ( 3710): #0      BluetoothDevice.connect.<anonymous closure> (package:flutter_blue/src/bluetooth_device.dart:33:9)
E/flutter ( 3710): #1      _rootRun (dart:async/zone.dart:1346:47)
E/flutter ( 3710): #2      _CustomZone.run (dart:async/zone.dart:1258:19)
E/flutter ( 3710): #3      _CustomZone.runGuarded (dart:async/zone.dart:1162:7)
E/flutter ( 3710): #4      _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:1202:23)
E/flutter ( 3710): #5      _rootRun (dart:async/zone.dart:1354:13)
E/flutter ( 3710): #6      _CustomZone.run (dart:async/zone.dart:1258:19)
E/flutter ( 3710): #7      _CustomZone.bindCallback.<anonymous closure> (dart:async/zone.dart:1186:23)
E/flutter ( 3710): #8      Timer._createTimer.<anonymous closure> (dart:async-patch/timer_patch.dart:18:15)
E/flutter ( 3710): #9      _Timer._runTimers (dart:isolate-patch/timer_impl.dart:395:19)
E/flutter ( 3710): #10     _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:426:5)
E/flutter ( 3710): #11     _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)
E/flutter ( 3710): 

我看到堆栈跟踪从 BluetoothDevice#connect() 开始,但我不确定该怎么做。

我也尝试在 BluetoothDevice#connect() 返回的 Future<void> 上调用 then((_) {}, (o) => print("caught ${o.runtimeType}")) 然后在 try-catch 中等待它,但我没有成功。

有什么想法吗?

您使用的包中的 connect 方法写得不好。你没有做错任何事,不管是谁写的代码。如果您浏览该存储库的 GitHub 问题部分,您会发现很多问题和与此问题相关的拉取请求,例如 this 和它链接的 issues/PR。

计时器回调中的代码存在于实例化计时器的函数之外。无法直接捕获计时器回调中抛出的错误。

如果你想要超时,不要使用这个包提供的功能,使用原生的 Dart timeout 函数。

try {
  await (device as BluetoothDevice).connect().timeout(Duration(seconds: 1));
} catch (o) {
  print("caught ${o.runtimeType}");
}