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

Flutter结合Riverpod:使用服务类刷新视图遇问题求助

问题原因及解决方案

你的代码里ListView没反应,核心问题有两个:

  1. 用了Provider来管理蓝牙服务,但Provider是不可变状态提供者,内部数据变化时不会通知Riverpod触发UI刷新
  2. modulesScanned是普通List,直接添加元素不会让Riverpod感知到状态变化

修复步骤

1. 把蓝牙服务改成StateNotifier+StateNotifierProvider

StateNotifier是Riverpod专门用来管理可变状态的类,状态更新时会自动通知UI重建。

修改BluetoothService.dart:

import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';
import 'Module.dart';

// 改成StateNotifierProvider,泛型第一个是服务类,第二个是状态类型(这里是Module列表)
final bluetoothServiceProvider = StateNotifierProvider<BluetoothService, List<Module>>((ref) => BluetoothService(ref));

class BluetoothService extends StateNotifier<List<Module>> {
  final Ref ref;
  final FlutterReactiveBle flutterReactiveBle = FlutterReactiveBle();
  StreamSubscription? subscriptionDiscoverDevices;

  // 初始化状态为空列表
  BluetoothService(this.ref) : super([]);

  Future<void> discoverDevices() async {
    // 先清空之前的扫描结果,避免重复
    state = [];
    // 取消之前的订阅,防止多次扫描导致内存泄漏
    subscriptionDiscoverDevices?.cancel();
    
    subscriptionDiscoverDevices = flutterReactiveBle.scanForDevices(withServices: [SERVICE_UUID]).listen((device) {
      // 必须创建新列表更新state(StateNotifier要求状态不可变)
      // 可选:去重,避免同一设备多次添加
      if (!state.any((module) => module.name == device.name)) {
        state = [...state, Module(name: device.name)];
      }
    }, onError: (error) {
      print("蓝牙扫描错误: $error");
    });
  }

  // 销毁时取消订阅,释放资源
  @override
  void dispose() {
    subscriptionDiscoverDevices?.cancel();
    super.dispose();
  }
}

2. 更新UI层代码

现在可以直接watch状态列表,简化MyView.dart:

class ModulesDiscoverView extends ConsumerWidget {
  const ModulesDiscoverView({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    // 直接watch状态列表
    final scannedModules = ref.watch(bluetoothServiceProvider);
    
    return Scaffold(
      body: Column(
        children: [
          ElevatedButton(
            // 通过notifier调用服务方法
            onPressed: () => ref.read(bluetoothServiceProvider.notifier).discoverDevices(),
            child: const Text("Discover devices"),
          ),
          Expanded(
            child: ListView.builder(
              itemCount: scannedModules.length,
              itemBuilder: (context, index) {
                final module = scannedModules[index];
                return Text(module.name);
              },
            ),
          ),
        ],
      ),
    );
  }
}

额外注意事项

  • 确保SERVICE_UUID是正确的蓝牙服务UUID,否则扫描不到目标设备
  • 检查蓝牙权限:Android需要位置权限+蓝牙权限,iOS需要蓝牙权限,权限不足会导致扫描失败
  • 如果设备名称为空,可以改用device.id显示,避免UI出现空白文本

内容的提问来源于stack exchange,提问作者Naografix

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 08:32:25