已做空值检查仍出现Flutter蓝牙空值检查异常求助
问题排查与解决
问题场景
运行蓝牙连接代码时,成功打印Connected to the device后触发空值检查异常:
代码片段
void main() { WidgetsFlutterBinding.ensureInitialized(); runApp(const MyApp()); } // ... class BTConnection { BluetoothConnection? c; Future<void> connect(address) async { print('Connecting to the device ...'); BluetoothConnection connection = await BluetoothConnection.toAddress(address); c = connection; print('Connected to the device'); FlutterIsolate.spawn(listenToData, connection); } Future<void> disconnect() async { if (c != null) { await c?.finish(); print("disconnected from device"); } else { print("There is no bluetooth connection to disconnect"); } } @pragma('vm:entry-point') Future<void> listenToData(connection) async { print("listening ..."); await connection.input?.listen((Uint8List data) { print('Data incoming: ${ascii.decode(data)}'); connection.output.add(data); // Sending data }).onDone(() { print('Disconnected by remote request'); }); } }
错误日志
E/flutter (26066): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Null check operator used on a null value E/flutter (26066): #0 FlutterIsolate.spawn flutter_isolate.dart:28 E/flutter (26066): #1 BTConnection.connect main.dart:110 E/flutter (26066): <asynchronous suspension> E/flutter (26066): #2 _HomePageState.build.<anonymous closure> main.dart:70 E/flutter (26066): <asynchronous suspension> E/flutter (26066):
原因分析
FlutterIsolate的spawn方法要求传递的参数必须是可序列化类型(如基本类型、列表、Map或实现序列化协议的对象),但BluetoothConnection是包含原生资源引用的复杂对象,无法跨Isolate序列化传递。直接传递该对象会导致内部序列化失败,参数变为null,进而触发空值检查异常。
解决方法
方案1:通过通信端口传递数据
不直接传递BluetoothConnection,改用ReceivePort和SendPort在主Isolate与子Isolate间传递蓝牙数据:
- 修改
connect方法,创建通信端口并启动Isolate:
Future<void> connect(address) async { print('Connecting to the device ...'); BluetoothConnection connection = await BluetoothConnection.toAddress(address); c = connection; print('Connected to the device'); final receivePort = ReceivePort(); // 启动Isolate并传递SendPort await FlutterIsolate.spawn(listenToData, receivePort.sendPort); // 主Isolate监听蓝牙数据,转发到子Isolate connection.input?.listen((Uint8List data) { receivePort.sendPort.send(data); connection.output.add(data); // 处理回发数据 }).onDone(() { print('Disconnected by remote request'); receivePort.close(); }); }
- 修改子Isolate的监听逻辑:
@pragma('vm:entry-point') Future<void> listenToData(SendPort sendPort) async { print("listening ..."); final receivePort = ReceivePort(); sendPort.send(receivePort.sendPort); await for (final data in receivePort) { if (data is Uint8List) { print('Data incoming: ${ascii.decode(data)}'); } } }
方案2:在子Isolate内重建连接
将蓝牙地址(可序列化)传给子Isolate,在子Isolate内部直接建立连接并监听:
Future<void> connect(address) async { print('Starting isolate to handle bluetooth connection'); await FlutterIsolate.spawn(listenToData, address); } @pragma('vm:entry-point') Future<void> listenToData(String address) async { print("Connecting in isolate ..."); BluetoothConnection connection = await BluetoothConnection.toAddress(address); print("listening ..."); await connection.input?.listen((Uint8List data) { print('Data incoming: ${ascii.decode(data)}'); connection.output.add(data); }).onDone(() { print('Disconnected by remote request'); connection.finish(); }); }
注:此方案下主Isolate无法直接控制连接断开,需额外通过通信端口发送断开指令。
额外注意事项
- 确保
listenToData方法保留@pragma('vm:entry-point')注解,避免release模式下被混淆移除。 - 处理Isolate关闭时的资源释放,防止内存泄漏或连接残留。
内容的提问来源于stack exchange,提问作者Lauritz Tieste
相关产品推荐
相关产品推荐

