You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 13:32:08