Flutter Provider

345 阅读2分钟

Flutter Provider

  • Provider 是 Flutter 官方推荐的状态管理库,基于 InheritedWidget 和 ChangeNotifier 实现跨组件状态共享与响应式更新,是一个轻量级的状态管理解决方案,旨在简化复杂的状态管理流程,从而能够更高效地管理应用中的状态共享逻辑,同时保持代码的可读性和可维护性

ChangeNotifierProvider

  • 状态提供者,继承自 InheritedProvider(InheritProvider 本质上是 InheritWidget 实现的),用于状态数据管理
  • 结合 ChangeNotifier 类,当状态变化时通知依赖的 Widget 更新

Consumer

  • 状态消费者,用于监听状态数据变化并触发 builder 中的 UI 更新
  • 支持局部刷新 UI,仅重新构建依赖状态的部分 Widget,避免不必要的重建,推荐缩小 Consumer 范围,仅在需要更新的 Widget 上使用 Consumer,减少开销
  • 监听整个数据模型对象(完整状态),任何属性变化都会引起 Consumer 重建(即使属性未被使用)
//...
Consumer<CounterNotifier>(
  builder: (context, counterNotifier, child) {
    return Text('count: ${counterNotifier.count}');
  },
  child: const Icon(Icons.add), //通过 child 参数传递无需重建的子组件
);
//...

Selector

  • 用于对 Provider 提供的数据字段进行选择过滤,通过关注数据模型对象中的部分属性来优化性能(通过 selector 函数筛选指定字段,只有当所选择的部分属性数据改变时,才会触发重新构建)
  • Selector 提供了比 Consumer 更精细的控制,支持通过 shouldRebuild 自定义比较逻辑(默认用 == 比较)
//...
Selector<CounterNotifier, int>(
  selector: (context, counterNotifier) => counterNotifier.count, //假设 CounterNotifier 维护了多个字段,只监听其中的 count 字段
  builder: (context, count, child) {
    return Text('count: $count');
  },
  child: const Icon(Icons.add), //通过 child 参数传递无需重建的子组件
);
//...

Provider.of、context.read 和 context.watch

  • 直接获取状态(不监听变化)
//不监听状态变化,仅获取状态,不会触发当前组件重建
Provider.of<CounterNotifier>(context, listen: false).increment();
//不能在 build 方法内调用
context.read<CounterNotifier>().increment(); //内部就是 Provider.of<T>(this, listen: false)
//主动监听状态变化,当状态变化时触发组件重建(只能在 build 方法内调用),watch 内部本质是 dependOnInheritedWidgetOfExactType 方法的封装
context.watch<CounterNotifier>().increment(); //内部就是 Provider.of<T>(this)

Provider 使用流程

1 创建自定义 ChangeNotifier 提供状态管理

//Model 用于管理状态并触发通知
class CounterNotifier with ChangeNotifier { //mixin
//class CounterNotifier extends ChangeNotifier {
  int _count = 0; //私有字段

  //提供只读属性
  int get count => _count;

  void increment() {
    _count++; //修改状态
    notifyListeners(); //手动触发更新,通知所有监听者
  }
}

2 在 Widget 树中使用 Provider

void main() {
  runApp(
    //用 Provider 包裹子 Widget
    ChangeNotifierProvider(
      create: (context) => CounterNotifier(), //通过 ChangeNotifierProvider 提供状态
      child: const MyApp(),
    ),
  );
}

3 子 Widget 获取状态数据

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Scaffold(
      appBar: AppBar(title: const Text('Provider 示例')),
      body: Center(
        //通过 Consumer 来访问状态数据
        child: Consumer<CounterNotifier>(
          builder: (context, counterNotifier, child) {
            return Text("count: ${counterNotifier.count}");
          },
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          //通过 Provider.of 方法获取实例并获取状态数据
          final counterNotifier = Provider.of<CounterNotifier>(context, listen: false);
          counterNotifier.increment(); //直接调用方法
          print("count: ${counterNotifier.count}"); //直接访问属性
          //内部就是 Provider.of<T>(this, listen: false)
          final counterNotifier2 = context.read<CounterNotifier>();
          print("count2: ${counterNotifier2.count}");
        },
        child: const Icon(Icons.add),
      ),
    ));
  }
}