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 构建后执行。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,036评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,046评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,411评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,622评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,661评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,521评论 1 304
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,288评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,200评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,644评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,837评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,953评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,673评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,281评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,889评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,011评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,119评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,901评论 2 355

推荐阅读更多精彩内容