Flutter 实现一对多通知

在 Flutter 中,如果你想告知多个地方设备已连接,常见的方式是通过 状态管理 工具进行全局通知。可以使用 ProviderChangeNotifier 或者 Stream 来实现这种全局状态的更新,并在多个地方监听连接状态的变化。这里推荐使用 Provider + ChangeNotifier 的方式,因为它易于理解和使用。

使用 ChangeNotifier 通知多个地方设备已连接

  1. 定义 BluetoothConnectionNotifier:创建一个 ChangeNotifier 来管理设备连接状态。
  2. 全局提供 BluetoothConnectionNotifier:在顶层通过 ChangeNotifierProvider 进行状态管理。
  3. 监听设备连接状态:在需要的地方使用 ConsumerProvider.of 监听设备连接状态的变化。

具体步骤

1. 定义 BluetoothConnectionNotifier

这个类负责管理蓝牙设备的连接状态,并通过 notifyListeners() 通知监听者状态的变化。

import 'package:flutter/material.dart';

class BluetoothConnectionNotifier extends ChangeNotifier {
  bool _isConnected = false;

  bool get isConnected => _isConnected;

  void setConnected(bool connected) {
    _isConnected = connected;
    notifyListeners(); // 通知所有监听者状态发生变化
  }
}

2. 在顶层提供 BluetoothConnectionNotifier

你可以在应用的根部,或者在需要监听的页面上,使用 ChangeNotifierProvider 提供 BluetoothConnectionNotifier

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

void main() {
  runApp(
    ChangeNotifierProvider(
      create: (_) => BluetoothConnectionNotifier(),
      child: MyApp(),
    ),
  );
}

3. 连接设备并通知其他地方

当设备连接成功后,通过 BluetoothConnectionNotifier 来更新连接状态,这样所有监听者都会收到通知。

void onBluetoothConnected(BuildContext context) {
  // 当设备连接成功时,通知连接状态变化
  final bluetoothNotifier = Provider.of<BluetoothConnectionNotifier>(context, listen: false);
  bluetoothNotifier.setConnected(true); // 设置连接状态为已连接
}

4. 在多个地方监听连接状态

通过 ConsumerProvider.of,在需要的地方监听连接状态的变化。可以在多个页面或者组件中监听。

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

class SomeWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Consumer<BluetoothConnectionNotifier>(
      builder: (context, bluetoothNotifier, child) {
        return Text(
          bluetoothNotifier.isConnected ? '设备已连接' : '设备未连接',
          style: TextStyle(fontSize: 20),
        );
      },
    );
  }
}

5. 其它组件也可以通过 BluetoothConnectionNotifier 获取状态

如果在其他页面或组件中,也可以随时通过 Provider.of 获取连接状态。

bool isDeviceConnected(BuildContext context) {
  final bluetoothNotifier = Provider.of<BluetoothConnectionNotifier>(context);
  return bluetoothNotifier.isConnected;
}

总结

  • 通过 ChangeNotifier 管理设备连接状态。
  • 使用 ChangeNotifierProvider 提供全局状态。
  • 通过 ConsumerProvider.of 在多个地方监听状态变化,从而做到多个地方都可以响应设备的连接状态。

这样,当蓝牙设备连接成功后,所有监听连接状态的地方都会自动收到通知并更新 UI。

要在 ViewModel 中监听全局状态(比如蓝牙设备的连接状态),你可以通过 Provider 或者 ChangeNotifier 来监听状态的变化。关键步骤是:ViewModel 内部注册监听器,并确保 ViewModel 知道什么时候更新它的状态。

具体步骤:

1. 在 ViewModel 内部监听 BluetoothConnectionNotifier

可以在 ViewModel 中通过 Provider 获取 BluetoothConnectionNotifier,并在 init 阶段设置一个监听器,监听连接状态的变化。这里假设你的 ViewModel 继承自 ChangeNotifier,这样它可以在状态变化时通知 UI。

2. 通过 ProviderBuildContext 获取 BluetoothConnectionNotifier

为了确保 ViewModel 能够监听到 BluetoothConnectionNotifier 的状态变化,你需要在 ViewModel 初始化时获取 BluetoothConnectionNotifier,然后在 notifyListeners 时更新 ViewModel

代码实现

1. ViewModel 中监听 BluetoothConnectionNotifier

假设我们有一个 BluetoothScanViewModel,它需要监听蓝牙设备的连接状态,并在状态变化时做出响应。

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'bluetooth_connection_notifier.dart'; // 你定义的蓝牙连接状态管理类

class BluetoothScanViewModel extends ChangeNotifier {
  bool _isConnected = false;

  bool get isConnected => _isConnected;

  /// 初始化方法
  void init(BuildContext context) {
    // 获取 BluetoothConnectionNotifier 实例并监听状态变化
    final bluetoothNotifier = Provider.of<BluetoothConnectionNotifier>(context, listen: false);

    // 监听蓝牙连接状态的变化
    bluetoothNotifier.addListener(() {
      _isConnected = bluetoothNotifier.isConnected;
      // 状态变化时,通知UI更新
      notifyListeners();
    });
  }

  /// 处理其他业务逻辑
  void performSomeAction() {
    if (_isConnected) {
      // 设备已连接,执行一些逻辑
      print("设备已连接");
    } else {
      // 设备未连接,处理未连接逻辑
      print("设备未连接");
    }
  }
}

2. 在 Widget 中初始化 ViewModel

你需要在页面中调用 ViewModelinit 方法,确保它能够在构建的时候监听到 BluetoothConnectionNotifier 的状态变化。

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'bluetooth_scan_viewmodel.dart';
import 'bluetooth_connection_notifier.dart';

class BluetoothScanPage extends StatefulWidget {
  @override
  _BluetoothScanPageState createState() => _BluetoothScanPageState();
}

class _BluetoothScanPageState extends State<BluetoothScanPage> {
  late BluetoothScanViewModel viewModel;

  @override
  void initState() {
    super.initState();
    // 使用 WidgetsBinding 确保在 build 之后调用 viewModel 的 init 方法
    WidgetsBinding.instance.addPostFrameCallback((_) {
      viewModel.init(context); // 初始化 ViewModel 的监听器
    });
  }

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (_) => BluetoothScanViewModel(),
      child: Consumer<BluetoothScanViewModel>(
        builder: (context, viewModel, child) {
          return Scaffold(
            appBar: AppBar(
              title: Text(viewModel.isConnected ? "设备已连接" : "设备未连接"),
            ),
            body: Center(
              child: ElevatedButton(
                onPressed: viewModel.performSomeAction, // 执行逻辑
                child: Text("执行操作"),
              ),
            ),
          );
        },
      ),
    );
  }
}

关键点解释:

  1. 监听 BluetoothConnectionNotifier:在 ViewModelinit 方法中,我们通过 Provider.of 获取全局的 BluetoothConnectionNotifier 实例,并注册了一个监听器,当 isConnected 状态变化时,调用 notifyListeners 通知 UI。

  2. WidgetsBinding.instance.addPostFrameCallback:为了确保在 initState 中能够访问 BuildContext,我们使用了 WidgetsBinding.instance.addPostFrameCallback 来推迟调用 ViewModel 的初始化,避免在 initState 中直接使用 BuildContext 报错。

  3. performSomeActionViewModel 的方法可以根据 isConnected 的状态进行不同的业务逻辑处理。

总结:

  • ViewModel 中通过 Provider 获取 BluetoothConnectionNotifier,并设置监听器。
  • 当状态变化时,通过 notifyListeners 通知 UI 更新。
  • 使用 WidgetsBinding.instance.addPostFrameCallback 确保 ViewModelinit 能够在正确的 BuildContext 构建后执行。
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容