Flutter开发:解决LateInitializationError(device未初始化)问题
解决Flutter Blue中LateInitializationError: Field 'device' has not been initialized错误
问题原因
- 用
late声明device和_heartRate变量,但在未完成初始化前就在build方法中访问(比如device == null的判断),而late变量要求首次访问前必须完成初始化,否则直接抛出LateError。 late修饰的变量不能为null,所以device == null的判断逻辑本身不成立——未初始化的late变量会直接报错,而非返回null。scanResults.firstWhere的orElse回调直接抛出异常,会导致扫描不到设备时程序崩溃,无法正常处理未找到设备的场景。
修复方案
- 将
device和_heartRate改为可空类型(去掉late,声明为BluetoothDevice?和int?),或给_heartRate设置初始值。 - 用
where(...).firstOrNull替代firstWhere(Dart 2.12+支持),避免找不到设备时抛出异常。 - 在
build方法中处理变量未初始化的情况,比如显示加载状态或提示文本。 - 优化错误处理,避免直接抛出异常,改为打印日志或提示用户。
修改后的完整代码
import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_blue/flutter_blue.dart'; class HeartRatePage extends StatefulWidget { @override _HeartRatePageState createState() => _HeartRatePageState(); } class _HeartRatePageState extends State<HeartRatePage> { FlutterBlue flutterBlue = FlutterBlue.instance; BluetoothDevice? device; // 改为可空类型,初始为null BluetoothCharacteristic? _heartRateMeasurementCharacteristic; // 同样改为可空 StreamSubscription<List<int>>? _streamSubscription; int _heartRate = 0; // 给心率设置初始值,避免未初始化问题 @override void initState() { super.initState(); startScan(); } void startScan() { flutterBlue.startScan(timeout: const Duration(seconds: 4)); flutterBlue.scanResults.listen((results) { // 使用firstOrNull替代firstWhere,避免抛出异常 final foundDevice = results.firstWhereOrNull( (r) => r.device.name == 'Heart Rate', ); if (foundDevice != null && device == null) { // 避免重复连接 connectToDevice(foundDevice.device); } }); // 扫描结束后如果未找到设备,更新状态 flutterBlue.isScanning.listen((isScanning) { if (!isScanning && device == null) { setState(() {}); } }); } @override void dispose() { _streamSubscription?.cancel(); device?.disconnect(); // 页面销毁时断开设备连接 super.dispose(); } void connectToDevice(BluetoothDevice _device) async { setState(() { device = _device; }); try { await device?.connect(); final services = await device?.discoverServices(); if (services == null) return; // 查找心率服务 final heartRateService = services.firstWhereOrNull( (s) => s.uuid.toString() == '0000180d-0000-1000-8000-00805f9b34fb', ); if (heartRateService == null) { print('未找到心率服务'); return; } // 查找心率测量特征 _heartRateMeasurementCharacteristic = heartRateService.characteristics.firstWhereOrNull( (c) => c.uuid.toString() == '00002a37-0000-1000-8000-00805f9b34fb', ); if (_heartRateMeasurementCharacteristic == null) { print('未找到心率测量特征'); return; } // 监听心率数据 _streamSubscription = _heartRateMeasurementCharacteristic?.value.listen((value) { // 解析心率数据(兼容8位和16位格式) int heartRate; if ((value[0] & 0x01) == 0) { // 心率是8位无符号整数 heartRate = value[1]; } else { // 心率是16位无符号整数 heartRate = (value[1] << 8) | value[2]; } setState(() { _heartRate = heartRate; }); print('当前心率: $heartRate bpm'); }); } on Exception catch (e) { print('连接或获取数据失败: $e'); setState(() { device = null; }); } } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: const Color.fromARGB(255, 245, 245, 245), appBar: AppBar( leading: IconButton( icon: const Icon(Icons.arrow_back_ios_new, color: Color(0xFF61D2A4)), onPressed: () => Navigator.of(context).pop(), ), title: const Text( 'Heart Rate', style: TextStyle(fontFamily: 'Roboto', fontWeight: FontWeight.bold), ), centerTitle: true, foregroundColor: Colors.black, backgroundColor: Colors.white, ), body: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ if (device == null) const Center(child: Text('正在搜索心率设备...')) else Center( child: Text( '心率: $_heartRate bpm', style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold), ), ), ], ), ); } }
额外说明
- 使用
firstWhereOrNull需要Dart版本2.12以上,若版本较低,可用where(...).toList().firstOrNull替代。 - 心率数据解析做了格式兼容,适配更多支持标准蓝牙心率协议的设备。
- 页面销毁时添加了设备断开逻辑,避免资源泄漏。
内容的提问来源于stack exchange,提问作者Nutdanai
相关产品推荐
相关产品推荐

