Flutter页面参数传递优化:避免重复传递蓝牙设备参数
解决Flutter页面间重复传递蓝牙设备参数的问题
不用再每个页面都手动传polarDevice和breathingDevice了,下面给你三种实用的解决方法,按需选:
方法一:用InheritedWidget(轻量无依赖)
适合简单场景,不需要额外引入第三方库,直接通过Flutter原生组件实现参数共享。
步骤1:创建共享设备的InheritedWidget
class DeviceProviderWidget extends InheritedWidget { final BluetoothDevice polarDevice; final BluetoothDevice breathingDevice; const DeviceProviderWidget({ super.key, required this.polarDevice, required this.breathingDevice, required super.child, }); // 封装获取方法,方便子页面调用 static DeviceProviderWidget of(BuildContext context) { final widget = context.dependOnInheritedWidgetOfExactType<DeviceProviderWidget>(); assert(widget != null, "找不到DeviceProviderWidget,请检查是否在根节点包裹"); return widget!; } @override bool updateShouldNotify(covariant DeviceProviderWidget oldWidget) { // 设备实例变化时通知子页面更新 return polarDevice != oldWidget.polarDevice || breathingDevice != oldWidget.breathingDevice; } }
步骤2:在首页或根节点包裹这个组件
// 首页的build方法里,把整个页面包裹在DeviceProviderWidget中 @override Widget build(BuildContext context) { return DeviceProviderWidget( polarDevice: _polarDevice, // 你的蓝牙设备实例 breathingDevice: _breathingDevice, child: Scaffold( appBar: AppBar(title: const Text("首页")), body: const Center(child: Text("首页内容")), floatingActionButton: TextButton( onPressed: () { // 跳转时不用传参了! Navigator.push( context, MaterialPageRoute(builder: (context) => ProtocolListScreen()), ); }, child: const Text("去协议列表"), ), ), ); }
步骤3:子页面直接获取设备
// ProtocolListScreen里 class ProtocolListScreen extends StatelessWidget { const ProtocolListScreen({super.key}); @override Widget build(BuildContext context) { // 直接获取共享的设备 final deviceProvider = DeviceProviderWidget.of(context); final polarDevice = deviceProvider.polarDevice; final breathingDevice = deviceProvider.breathingDevice; return Scaffold( appBar: AppBar(title: const Text("协议列表")), body: ListView.builder( itemCount: protocols.length, itemBuilder: (context, index) { final protocol = protocols[index]; return ListTile( title: Text(protocol['name']), trailing: TextButton( onPressed: () { if (protocol['name'] == 'Anulom Vilom Pranayam') { // 跳转到AnulomVilomScreen也不用传参! Navigator.push( context, MaterialPageRoute(builder: (context) => AnulomVilomScreen()), ); } }, child: const Text("进入"), ), ); }, ), ); } }
// AnulomVilomScreen里同样获取 class AnulomVilomScreen extends StatelessWidget { const AnulomVilomScreen({super.key}); @override Widget build(BuildContext context) { final deviceProvider = DeviceProviderWidget.of(context); // 直接用deviceProvider.polarDevice和breathingDevice return Scaffold( appBar: AppBar(title: const Text("Anulom Vilom")), body: Center(child: Text("使用蓝牙设备:${deviceProvider.polarDevice.name}")), ); } }
方法二:用Provider状态管理(适合复杂场景)
如果后续需要更新设备状态(比如重新连接蓝牙),用Provider更方便,需要先在pubspec.yaml里添加依赖:
dependencies: flutter: sdk: flutter provider: ^6.0.5
步骤1:创建设备状态管理类
class DeviceNotifier extends ChangeNotifier { BluetoothDevice _polarDevice; BluetoothDevice _breathingDevice; DeviceNotifier(this._polarDevice, this._breathingDevice); // 对外暴露获取方法 BluetoothDevice get polarDevice => _polarDevice; BluetoothDevice get breathingDevice => _breathingDevice; // 如果需要更新设备,添加方法并通知页面刷新 void updatePolarDevice(BluetoothDevice newDevice) { _polarDevice = newDevice; notifyListeners(); } }
步骤2:在根节点包裹Provider
void main() { // 假设已经初始化了蓝牙设备实例 final polarDevice = ...; final breathingDevice = ...; runApp( ChangeNotifierProvider( create: (context) => DeviceNotifier(polarDevice, breathingDevice), child: const MyApp(), ), ); }
步骤3:子页面获取设备
// ProtocolListScreen里,用Consumer避免不必要的页面重建 class ProtocolListScreen extends StatelessWidget { const ProtocolListScreen({super.key}); @override Widget build(BuildContext context) { return Consumer<DeviceNotifier>( builder: (context, deviceNotifier, child) { return Scaffold( appBar: AppBar(title: const Text("协议列表")), body: ListTile( title: const Text("Anulom Vilom Pranayam"), trailing: TextButton( onPressed: () { Navigator.push(context, MaterialPageRoute(builder: (context) => AnulomVilomScreen())); }, child: const Text("进入"), ), ), ); }, ); } }
方法三:全局单例(谨慎使用)
适合临时快速解决,但要注意设备实例的生命周期,避免内存泄漏:
class DeviceManager { // 单例实例 static final DeviceManager _instance = DeviceManager._internal(); factory DeviceManager() => _instance; DeviceManager._internal(); // 存储蓝牙设备 BluetoothDevice? polarDevice; BluetoothDevice? breathingDevice; }
使用方式
在首页初始化设备:
// 连接蓝牙成功后 DeviceManager().polarDevice = _polarDevice; DeviceManager().breathingDevice = _breathingDevice;
子页面直接调用:
final polarDevice = DeviceManager().polarDevice!; final breathingDevice = DeviceManager().breathingDevice!;
选哪个?
- 简单场景、不需要状态更新:用InheritedWidget,轻量无依赖
- 需要更新设备状态、复杂业务:用Provider/Riverpod等状态管理库
- 临时快速解决:用全局单例,但不推荐长期维护的项目使用
内容的提问来源于stack exchange,提问作者Aditya Ranjan
相关产品推荐
相关产品推荐

