Flutter Provider 状态管理深度指南

Flutter Provider 状态管理深度指南

本文档深入解析 Flutter Provider 状态管理库的核心原理、各类 Provider 的用法,并通过多个复杂场景示例详细讲解每个环节的实现方式。


目录

  1. 概述与核心原理
  2. [Provider 类型详解](#Provider 类型详解 "#2-provider-%E7%B1%BB%E5%9E%8B%E8%AF%A6%E8%A7%A3")
  3. 读取值的方式
  4. 场景一:基础计数器应用
  5. [场景二:多 Provider 依赖与 ProxyProvider](#场景二:多 Provider 依赖与 ProxyProvider "#5-%E5%9C%BA%E6%99%AF%E4%BA%8C%E5%A4%9A-provider-%E4%BE%9D%E8%B5%96%E4%B8%8E-proxyprovider")
  6. [场景三:异步数据 FutureProvider](#场景三:异步数据 FutureProvider "#6-%E5%9C%BA%E6%99%AF%E4%B8%89%E5%BC%82%E6%AD%A5%E6%95%B0%E6%8D%AE-futureprovider")
  7. [场景四:流式数据 StreamProvider](#场景四:流式数据 StreamProvider "#7-%E5%9C%BA%E6%99%AF%E5%9B%9B%E6%B5%81%E5%BC%8F%E6%95%B0%E6%8D%AE-streamprovider")
  8. 场景五:购物车与复杂业务状态
  9. [场景六:性能优化 Selector 与 Consumer](#场景六:性能优化 Selector 与 Consumer "#9-%E5%9C%BA%E6%99%AF%E5%85%AD%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96-selector-%E4%B8%8E-consumer")
  10. 场景七:接口与实现分离
  11. 组件化项目中的用法
  12. 常见问题与最佳实践

1. 概述与核心原理

1.1 什么是 Provider

Provider 是 Flutter 官方推荐的状态管理 方案之一,是对 InheritedWidget 的封装,使其更易用、更易复用。它由 Remi Rousselet 开发,是 Flutter Favorite 认证包。

核心优势:

特性 说明
资源管理 自动处理对象的创建、监听和销毁
懒加载 默认延迟创建,仅在首次被消费时创建
代码简洁 大幅减少 InheritedWidget 的样板代码
DevTools 支持 可在 Flutter DevTools 中查看应用状态
统一消费模式 context.watchcontext.readConsumerSelector
可扩展性 针对 ChangeNotifier 等监听机制做了优化

1.2 依赖安装

yaml 复制代码
# pubspec.yaml
dependencies:
  flutter:
    sdk: flutter
  provider: ^6.1.0

1.3 工作原理简述

scss 复制代码
┌─────────────────────────────────────────────────────────────┐
│                    Widget Tree                                │
│  ┌─────────────────────────────────────────────────────┐    │
│  │  MultiProvider / ChangeNotifierProvider              │    │
│  │  (在 InheritedWidget 中存储状态对象)                   │    │
│  │  ┌───────────────────────────────────────────────┐   │    │
│  │  │  Child Widget 1  → context.watch() 监听变化    │   │    │
│  │  │  Child Widget 2  → context.read()  仅读取      │   │    │
│  │  │  Child Widget 3  → context.select() 选择性监听 │   │    │
│  │  └───────────────────────────────────────────────┘   │    │
│  └─────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────┘

当 ChangeNotifier.notifyListeners() 被调用时:
  → 所有通过 watch/select 监听的 Widget 会重建
  → 通过 read 获取的 Widget 不会重建

2. Provider 类型详解

2.1 类型对照表

Provider 类型 适用场景 说明
Provider 不可变值、简单对象 最基础形式,直接暴露值
ChangeNotifierProvider 可变状态、业务逻辑 监听 ChangeNotifier,自动调用 dispose
ListenableProvider 任意 Listenable ChangeNotifierProvider 的父类
FutureProvider 异步初始化数据 监听 Future,完成时更新
StreamProvider 流式数据 监听 Stream,每次 emit 时更新
ProxyProvider 依赖其他 Provider 派生 组合多个 Provider 生成新值
ChangeNotifierProxyProvider 依赖其他 Provider 的 ChangeNotifier ProxyProvider + ChangeNotifier

2.2 创建 vs 复用

创建新对象(推荐):

dart 复制代码
ChangeNotifierProvider(
  create: (_) => MyModel(),  // 在 create 中创建
  child: MyApp(),
)

复用已有对象:

dart 复制代码
MyModel existingModel = MyModel();

ChangeNotifierProvider.value(
  value: existingModel,  // 使用 .value 构造函数
  child: MyApp(),
)

⚠️ 注意 :用默认构造函数传入已有对象会导致 Provider 在 dispose 时错误地调用 existingModel.dispose(),可能引发问题。


3. 读取值的方式

3.1 context.watch<T>()

作用 :监听 Provider,当值变化时触发当前 Widget 重建

dart 复制代码
Widget build(BuildContext context) {
  final counter = context.watch<Counter>();
  return Text('${counter.count}');
}
  • 适用于:需要根据状态更新 UI 的场景
  • 注意:在 build 内调用,每次 Counter 变化都会重建

3.2 context.read<T>()

作用 :仅读取值,不监听,不会因变化而重建。

dart 复制代码
FloatingActionButton(
  onPressed: () => context.read<Counter>().increment(),
  child: Icon(Icons.add),
)
  • 适用于:事件回调、initStatedidChangeDependencies
  • ⚠️ 不能在 build 中调用(会导致逻辑错误)

3.3 context.select<T, R>()

作用 :只监听对象的部分属性,只有该部分变化时才重建。

dart 复制代码
// 仅当 person.name 变化时重建
final name = context.select((Person p) => p.name);
return Text(name);
  • 适用于:大对象中只关心少量字段时的性能优化

3.4 Provider.of 等价写法

dart 复制代码
// 等价于 watch
Provider.of<Counter>(context)

// 等价于 read
Provider.of<Counter>(context, listen: false)

4. 场景一:基础计数器应用

4.1 需求

实现一个简单计数器:点击按钮数字 +1,界面实时更新。

4.2 状态模型

dart 复制代码
import 'package:flutter/foundation.dart';

class Counter with ChangeNotifier, DiagnosticableTreeMixin {
  int _count = 0;

  int get count => _count;

  void increment() {
    _count++;
    notifyListeners();  // 通知所有监听者重建
  }

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties.add(IntProperty('count', count));  // DevTools 中可读
  }
}

要点:

  • ChangeNotifier:提供 notifyListeners()
  • DiagnosticableTreeMixin:便于 DevTools 调试
  • 修改状态后必须调用 notifyListeners()

4.3 注入 Provider

dart 复制代码
void main() {
  runApp(
    ChangeNotifierProvider(
      create: (_) => Counter(),
      child: const MyApp(),
    ),
  );
}

4.4 消费状态

dart 复制代码
// 显示数字的 Widget - 需要监听
class Count extends StatelessWidget {
  const Count({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Text(
      '${context.watch<Counter>().count}',
      style: Theme.of(context).textTheme.headlineMedium,
    );
  }
}

// 按钮 - 只需触发操作,不监听
class IncrementButton extends StatelessWidget {
  const IncrementButton({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return FloatingActionButton(
      onPressed: () => context.read<Counter>().increment(),
      child: const Icon(Icons.add),
    );
  }
}

设计说明 :将 Count 抽成独立 Widget,只有它会在 Counter 变化时重建,避免整个页面重建。


5. 场景二:多 Provider 依赖与 ProxyProvider

5.1 需求

  • 有一个 Counter
  • 有一个 Translations,其内容依赖 Counter 的值
  • Translations 需要在 Counter 变化时自动更新

5.2 实现

dart 复制代码
class Counter with ChangeNotifier {
  int _value = 0;
  int get value => _value;
  void increment() {
    _value++;
    notifyListeners();
  }
}

class Translations {
  const Translations(this._value);
  final int _value;
  String get title => '你点击了 $_value 次';
}

// 使用 ProxyProvider 建立依赖关系
Widget build(BuildContext context) {
  return MultiProvider(
    providers: [
      ChangeNotifierProvider(create: (_) => Counter()),
      ProxyProvider<Counter, Translations>(
        update: (_, counter, __) => Translations(counter.value),
      ),
    ],
    child: const Foo(),
  );
}

class Foo extends StatelessWidget {
  const Foo({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final translations = context.watch<Translations>();
    return Text(translations.title);
  }
}

5.3 ProxyProvider 变体

类型 依赖数量 说明
ProxyProvider<A, R> 1 个 依赖 A,产出 R
ProxyProvider2<A, B, R> 2 个 依赖 A、B,产出 R
ProxyProvider3<A, B, C, R> 3 个 依赖 A、B、C,产出 R
ChangeNotifierProxyProvider<A, R> 1 个 产出的 R 是 ChangeNotifier

示例:依赖两个 Provider

dart 复制代码
ProxyProvider2<UserRepository, SettingsRepository, AppConfig>(
  update: (_, userRepo, settingsRepo, __) {
    return AppConfig(
      userId: userRepo.currentUserId,
      theme: settingsRepo.theme,
    );
  },
  child: MyApp(),
)

6. 场景三:异步数据 FutureProvider

6.1 需求

从网络或本地加载配置,加载中显示 Loading,完成后显示内容。

6.2 实现

dart 复制代码
FutureProvider<AppConfig?>(
  initialData: null,  // 5.0+ 必须提供,加载期间使用此值
  create: (context) => fetchConfigFromNetwork(),
  child: MyApp(),
)

// 消费:watch 得到的是 T?,加载中为 initialData,完成后为实际值
class ConfigConsumer extends StatelessWidget {
  const ConfigConsumer({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final config = context.watch<AppConfig?>();

    if (config == null) {
      return const CircularProgressIndicator();
    }
    return Text('主题: ${config.theme}');
  }
}

说明 :provider 包的 FutureProvider 直接暴露 T? 类型。加载中为 initialData,完成或出错后更新。如需区分 loading/data/error,可配合 FutureBuilder 或自定义包装类。

6.3 结合 ProxyProvider 使用

dart 复制代码
MultiProvider(
  providers: [
    Provider<AuthService>(create: (_) => AuthService()),
    FutureProvider<User?>(
      initialData: null,
      create: (context) => context.read<AuthService>().getCurrentUser(),
    ),
    ProxyProvider<User?, UserProfile?>(
      update: (_, user, __) => user == null ? null : UserProfile(user),
    ),
  ],
  child: MyApp(),
)

7. 场景四:流式数据 StreamProvider

7.1 需求

实时显示 WebSocket 消息、数据库变化、传感器数据等流式数据。

7.2 实现

dart 复制代码
MultiProvider(
  providers: [
    Provider<ChatService>(create: (_) => ChatService()),
    StreamProvider<ChatMessage>(
      initialData: ChatMessage.empty(),
      create: (context) => context.read<ChatService>().messageStream,
    ),
  ],
  child: const ChatPage(),
)

// 消费:watch 得到的是 Stream 最新一次 emit 的值
class LatestMessageTile extends StatelessWidget {
  const LatestMessageTile({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final message = context.watch<ChatMessage>();
    return ListTile(
      title: Text(message.content),
      subtitle: Text(message.timestamp.toString()),
    );
  }
}

7.3 捕获 Stream 错误

dart 复制代码
StreamProvider<int>.value(
  initialData: 0,
  value: myStream.handleError((e) => 0),
  child: MyApp(),
)

8. 场景五:购物车与复杂业务状态

8.1 需求

  • 商品列表、购物车、总价
  • 添加/删除商品、清空购物车
  • 多处 UI 需要同步更新

8.2 状态模型

dart 复制代码
class CartItem {
  final String id;
  final String name;
  final double price;
  final int quantity;

  CartItem({
    required this.id,
    required this.name,
    required this.price,
    this.quantity = 1,
  });

  CartItem copyWith({int? quantity}) => CartItem(
    id: id,
    name: name,
    price: price,
    quantity: quantity ?? this.quantity,
  );
}

class CartModel with ChangeNotifier {
  final List<CartItem> _items = [];

  List<CartItem> get items => List.unmodifiable(_items);

  int get itemCount => _items.fold(0, (sum, item) => sum + item.quantity);

  double get totalPrice =>
      _items.fold(0.0, (sum, item) => sum + item.price * item.quantity);

  void add(CartItem item) {
    final index = _items.indexWhere((i) => i.id == item.id);
    if (index >= 0) {
      _items[index] = _items[index].copyWith(
        quantity: _items[index].quantity + 1,
      );
    } else {
      _items.add(item);
    }
    notifyListeners();
  }

  void remove(String id) {
    _items.removeWhere((i) => i.id == id);
    notifyListeners();
  }

  void clear() {
    _items.clear();
    notifyListeners();
  }
}

8.3 注入与消费

dart 复制代码
void main() {
  runApp(
    ChangeNotifierProvider(
      create: (_) => CartModel(),
      child: const MyApp(),
    ),
  );
}

// 购物车图标 - 只关心数量
class CartBadge extends StatelessWidget {
  const CartBadge({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final count = context.select((CartModel c) => c.itemCount);
    return Badge(
      label: Text('$count'),
      child: Icon(Icons.shopping_cart),
    );
  }
}

// 总价 - 只关心 totalPrice
class CartTotal extends StatelessWidget {
  const CartTotal({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final total = context.select((CartModel c) => c.totalPrice);
    return Text('合计: ¥${total.toStringAsFixed(2)}');
  }
}

// 商品列表 - 需要完整 items
class CartItemList extends StatelessWidget {
  const CartItemList({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final cart = context.watch<CartModel>();
    return ListView.builder(
      itemCount: cart.items.length,
      itemBuilder: (_, i) {
        final item = cart.items[i];
        return ListTile(
          title: Text(item.name),
          subtitle: Text('x${item.quantity}'),
          trailing: IconButton(
            icon: Icon(Icons.delete),
            onPressed: () => context.read<CartModel>().remove(item.id),
          ),
        );
      },
    );
  }
}

要点 :使用 context.selectCartBadgeCartTotal 只在各自关心的字段变化时重建,避免不必要的刷新。


9. 场景六:性能优化 Selector 与 Consumer

9.1 问题

当状态对象很大时,context.watch<BigModel>() 会导致任何 BigModel 变化都触发重建,即使只用到其中一个字段。

9.2 使用 Selector

dart 复制代码
// 仅当 Person.name 变化时重建
class PersonName extends StatelessWidget {
  const PersonName({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final name = context.select((Person p) => p.name);
    return Text(name);
  }
}

9.3 使用 Consumer 限定重建范围

dart 复制代码
Foo(
  child: Consumer<CartModel>(
    builder: (context, cart, child) {
      return Column(
        children: [
          Text('${cart.itemCount} 件商品'),
          child!,  // child 不会因 cart 变化而重建
        ],
      );
    },
    child: const ExpensiveWidget(),  // 稳定的子组件
  ),
)

9.4 使用 Selector Widget

dart 复制代码
Selector<CartModel, int>(
  selector: (_, cart) => cart.itemCount,
  builder: (_, count, __) => Text('$count'),
)

10. 场景七:接口与实现分离

10.1 需求

  • 定义抽象接口 AuthService
  • 提供实现 FirebaseAuthService
  • UI 层只依赖接口,便于测试和替换实现

10.2 实现

dart 复制代码
abstract class AuthService with ChangeNotifier {
  User? get currentUser;
  Future<void> signIn(String email, String password);
  Future<void> signOut();
}

class FirebaseAuthService with ChangeNotifier implements AuthService {
  // 实现细节...
}

// 注入时指定接口类型,创建时返回实现
ChangeNotifierProvider<AuthService>(
  create: (_) => FirebaseAuthService(),
  child: MyApp(),
)

// 消费时使用接口类型
class ProfilePage extends StatelessWidget {
  const ProfilePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final auth = context.watch<AuthService>();
    return auth.currentUser == null
        ? LoginPage()
        : UserProfile(user: auth.currentUser!);
  }
}

11. 组件化项目中的用法

11.1 组件化项目结构

在模块化/组件化架构中,项目通常按功能或业务域拆分:

bash 复制代码
my_app/
├── app/                    # 主应用入口
│   └── main.dart
├── core/                   # 核心层(路由、主题、常量)
│   ├── router/
│   └── theme/
├── shared/                 # 共享层(公共组件、工具、基础 Provider)
│   ├── providers/          # 全局 Provider 定义
│   └── widgets/
├── modules/                # 业务模块
│   ├── auth/               # 登录注册模块
│   │   ├── providers/
│   │   ├── models/
│   │   └── views/
│   ├── home/               # 首页模块
│   └── profile/            # 个人中心模块
└── pubspec.yaml

11.2 分层注入策略

全局 Provider(应用根级)

main.dart 或根 Widget 注入跨模块共享的状态:

dart 复制代码
// app/main.dart
void main() {
  runApp(
    MultiProvider(
      providers: [
        // 全局:用户认证、主题、语言等
        ChangeNotifierProvider(create: (_) => AuthProvider()),
        ChangeNotifierProvider(create: (_) => ThemeProvider()),
        Provider<ApiClient>(create: (_) => ApiClientImpl()),
      ],
      child: const MyApp(),
    ),
  );
}
模块级 Provider(按需挂载)

仅在进入某模块时注入,离开时自动 dispose:

dart 复制代码
// modules/home/home_page.dart
class HomePage extends StatelessWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        // 仅首页需要的状态
        ChangeNotifierProvider(create: (_) => HomeFeedProvider()),
        ChangeNotifierProvider(create: (_) => BannerProvider()),
      ],
      child: const HomeView(),
    );
  }
}

好处 :未进入首页时不会创建 HomeFeedProvider,减少内存和初始化开销。

路由级 Provider(与 GoRouter/路由结合)
dart 复制代码
// 路由配置中为不同路由挂载不同 Provider
GoRoute(
  path: '/cart',
  builder: (context, state) => MultiProvider(
    providers: [
      ChangeNotifierProvider(create: (_) => CartProvider()),
    ],
    child: const CartPage(),
  ),
),

11.3 模块间共享状态

方式一:通过根级 Provider 共享

dart 复制代码
// shared/providers/cart_provider.dart
class CartProvider with ChangeNotifier {
  final List<CartItem> _items = [];
  // ...
}

// main.dart 根级注入
ChangeNotifierProvider(create: (_) => CartProvider()),

// 任意模块中消费
context.watch<CartProvider>()

方式二:通过 ChangeNotifierProxyProvider 依赖其他模块

dart 复制代码
// 购物车依赖当前用户(AuthProvider 需有 currentUserId,CartProvider 需有 userId 可写属性)
MultiProvider(
  providers: [
    ChangeNotifierProvider(create: (_) => AuthProvider()),
    ChangeNotifierProxyProvider<AuthProvider, CartProvider>(
      create: (_) => CartProvider(),
      update: (_, auth, cart) => cart!..userId = auth.currentUserId,
    ),
  ],
  child: MyApp(),
)

11.4 可复用组件的 Provider 可选依赖

组件可能在不同上下文中使用:有时在 Provider 内,有时在 Provider 外。使用可空类型避免强依赖:

dart 复制代码
// shared/widgets/optional_cart_badge.dart
class OptionalCartBadge extends StatelessWidget {
  const OptionalCartBadge({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // 找不到 CartProvider 时返回 null,不抛错
    final cart = context.watch<CartProvider?>();
    if (cart == null) return const SizedBox.shrink();

    return Badge(
      label: Text('${cart.itemCount}'),
      child: const Icon(Icons.shopping_cart),
    );
  }
}

11.5 模块内私有 Provider

模块内部状态不暴露给其他模块,仅在模块内使用:

dart 复制代码
// modules/auth/login_page.dart
class LoginPage extends StatelessWidget {
  const LoginPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (_) => LoginFormProvider(),  // 仅登录页使用
      child: const LoginView(),
    );
  }
}

11.6 依赖注入与模块解耦

通过接口 + Provider 实现模块解耦,便于单测和替换实现:

dart 复制代码
// core/contracts/auth_repository.dart(接口定义在 core)
abstract class AuthRepository {
  Future<User?> getCurrentUser();
  Future<void> signOut();
}

// modules/auth/data/auth_repository_impl.dart(实现在模块内)
class AuthRepositoryImpl implements AuthRepository {
  // ...
}

// AuthProvider 需有 repository 可写属性
// app/main.dart - 根级注入接口,实现由模块提供
MultiProvider(
  providers: [
    Provider<AuthRepository>(
      create: (_) => AuthRepositoryImpl(),
    ),
    ChangeNotifierProxyProvider<AuthRepository, AuthProvider>(
      create: (_) => AuthProvider(),
      update: (_, repo, auth) => auth!..repository = repo,
    ),
  ],
  child: MyApp(),
)

11.7 组件化项目中的 Provider 分层示意

scss 复制代码
┌─────────────────────────────────────────────────────────────────┐
│  main.dart - 根级 MultiProvider                                   │
│  ├── AuthProvider          (全局)                                │
│  ├── ThemeProvider         (全局)                                │
│  └── ApiClient             (全局)                                │
│       └── MyApp()                                                │
│            └── Router                                            │
│                 ├── /login  → LoginPage + LoginFormProvider      │
│                 ├── /home   → HomePage + HomeFeedProvider        │
│                 └── /cart   → CartPage + CartProvider            │
└─────────────────────────────────────────────────────────────────┘

规则:
• 全局、跨模块共享 → 根级
• 单模块、单页面 → 模块/路由级
• 可复用组件 → 使用 context.watch<T?>() 支持可选依赖

11.8 小结

场景 注入位置 示例
全局共享 main.dart 根级 AuthProvider、ThemeProvider
模块私有 模块/页面根 Widget LoginFormProvider、HomeFeedProvider
路由级 路由 builder 内 CartProvider(仅购物车页)
可选依赖 消费时用 T? context.watch<CartProvider?>()
模块解耦 接口 + Provider Provider<AuthRepository>

12. 常见问题与最佳实践

12.1 initState 中访问 Provider

错误:

dart 复制代码
@override
void initState() {
  super.initState();
  context.watch<Foo>().value;  // 会报错
}

正确:

dart 复制代码
@override
void initState() {
  super.initState();
  context.read<Foo>().fetchData();  // 不监听,只读取
}

12.2 在 initState 中触发可能同步的状态更新

错误:initState 中直接调用可能同步完成并触发 notifyListeners 的方法,会导致 build 阶段异常。

dart 复制代码
@override
void initState() {
  super.initState();
  context.read<MyNotifier>().fetchSomething();  // 若同步完成会触发 notifyListeners
}

正确: 使用 Future.microtask 推迟到当前帧之后执行。

dart 复制代码
@override
void initState() {
  super.initState();
  Future.microtask(() =>
    context.read<MyNotifier>().fetchSomething(),
  );
}

12.3 可选依赖(Provider 可能不存在)

dart 复制代码
// 找不到时抛错
context.watch<ThemeModel>()

// 找不到时返回 null
context.watch<ThemeModel?>()

12.4 同一类型多个 Provider

通过不同类型区分,而不是都用 String

dart 复制代码
Provider<Country>(create: (_) => Country('中国')),
Provider<City>(create: (_) => City('北京')),

12.5 热重载时重新初始化

dart 复制代码
class MyModel with ChangeNotifier implements ReassembleHandler {
  @override
  void reassemble() {
    // 热重载时调用
    reset();
  }
}

12.6 Provider 过多导致 StackOverflowError

  • 使用 lazy: false 分批加载
  • 在启动流程中分步挂载 Provider
  • 减少 MultiProvider 的嵌套层级

附录:快速参考

操作 代码
注入 ChangeNotifierProvider(create: (_) => Model(), child: ...)
监听并重建 context.watch<Model>()
只读不监听 context.read<Model>()
选择性监听 context.select<Model, R>((m) => m.field)
多 Provider MultiProvider(providers: [...], child: ...)
依赖派生 ProxyProvider<A, B>(update: (_, a, __) => B(a))

参考资源


相关推荐
JMchen1237 小时前
跨技术栈:在Flutter/Compose中应用自定义View思想
java·经验分享·flutter·canvas·dart·自定义view
国医中兴9 小时前
Flutter 三方库 ngrouter 鸿蒙适配指南 - 实现高性能扁平化路由导航管理实战
flutter·harmonyos·鸿蒙·openharmony
lpftobetheone10 小时前
【Flutter】如何理解Dart语言的Isolate API
flutter
国医中兴10 小时前
Flutter 三方库 inject_generator 的鸿蒙化适配指南 - 自动化依赖注入注入生成器、驱动鸿蒙大型工程解耦实战
flutter·harmonyos·鸿蒙·openharmony·inject_generator
chdo11 小时前
从需求到实现:Flutter可变宽度滑动器的探索之路
flutter
国医中兴12 小时前
Flutter 三方库 themed_color_palette 的鸿蒙化适配指南 - 定义语义化调色板、在鸿蒙端实现像素级的主题切换实战
flutter·harmonyos·鸿蒙·openharmony·themed_color_palette
不爱吃糖的程序媛12 小时前
2026 年如何上车 Flutter-OH:环境搭建与上手流程
flutter
国医中兴12 小时前
Flutter 三方库 aws_sqs_api 鸿蒙适配指南 - 实现分布式消息异步解耦、在 OpenHarmony 上打造高可用云端队列控制中枢实战
flutter·harmonyos·aws