flutter中provider的进阶用法小结(一)

Provider 是 Flutter 中非常流行的状态管理库,它使得管理应用的状态变得简单高效。我们可以使用 Provider 来管理不同的状态,包括应用的全局状态、局部状态,甚至是依赖注入。

进阶用法

除了简单的状态共享,Provider 还可以用于一些更复杂的场景,比如多层嵌套的依赖注入自动销毁资源状态变化监听 等。接下来我将介绍一些进阶用法,帮助你更好地理解和应用 Provider


1. ChangeNotifierConsumer 使用

最常见的 Provider 使用模式是通过 ChangeNotifierConsumer 进行状态管理。在这个模式下,ChangeNotifier 充当了管理状态的角色,并在状态变化时通知界面更新。

示例:
dart 复制代码
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

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

class Counter with ChangeNotifier {
  int _count = 0;

  int get count => _count;

  void increment() {
    _count++;
    notifyListeners(); // 通知消费者
  }
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Provider Example')),
        body: Center(
          child: Consumer<Counter>(
            builder: (context, counter, child) {
              return Text('Counter: ${counter.count}', style: TextStyle(fontSize: 24));
            },
          ),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            context.read<Counter>().increment(); // 增加计数
          },
          child: Icon(Icons.add),
        ),
      ),
    );
  }
}
关键点:
  • ChangeNotifierProviderChangeNotifierProvider 是将 ChangeNotifier 放到 widget 树中的一个方式,Counter 继承了 ChangeNotifier,并且通过 notifyListeners() 来通知变化。
  • Consumer<Counter>Consumer 用来监听 Counter 对象的变化,当状态变化时,builder 方法会被重新调用,刷新 UI。

2. 使用 Selector 优化性能

SelectorProvider 提供的一个优化组件,它可以帮助你精确地选择你需要的部分状态并监听变化,从而避免不必要的 UI 重建。与 Consumer 不同,Selector 只会在所选状态发生变化时重新构建 UI。

示例:
dart 复制代码
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

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

class Counter with ChangeNotifier {
  int _count = 0;
  int _otherValue = 0;

  int get count => _count;
  int get otherValue => _otherValue;

  void incrementCount() {
    _count++;
    notifyListeners();
  }

  void incrementOtherValue() {
    _otherValue++;
    notifyListeners();
  }
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Provider Selector Example')),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Selector<Counter, int>(
                selector: (context, counter) => counter.count,  // 只选择 count 属性
                builder: (context, count, child) {
                  return Text('Counter: $count', style: TextStyle(fontSize: 24));
                },
              ),
              Selector<Counter, int>(
                selector: (context, counter) => counter.otherValue, // 只选择 otherValue 属性
                builder: (context, otherValue, child) {
                  return Text('Other Value: $otherValue', style: TextStyle(fontSize: 24));
                },
              ),
            ],
          ),
        ),
        floatingActionButton: Column(
          mainAxisAlignment: MainAxisAlignment.end,
          children: [
            FloatingActionButton(
              onPressed: () {
                context.read<Counter>().incrementCount(); // 增加计数
              },
              child: Icon(Icons.add),
            ),
            SizedBox(height: 10),
            FloatingActionButton(
              onPressed: () {
                context.read<Counter>().incrementOtherValue(); // 增加 otherValue
              },
              child: Icon(Icons.add_alert),
            ),
          ],
        ),
      ),
    );
  }
}
关键点:
  • SelectorSelector 允许你只选择并监听状态的一部分。当 count 发生变化时,只会重新构建显示 count 的部分,而 otherValue 的部分不会重新构建,避免不必要的 UI 更新。
  • 优化性能Selector 是一个性能优化工具,用来减少不必要的 widget 重建。

3. 使用 Provider 实现依赖注入

Provider 不仅适用于状态管理,它还可以用来实现依赖注入(DI)。通过 Provider,你可以在应用中创建并注入单例或多个不同类型的对象,使得它们在整个应用中共享。

示例:
dart 复制代码
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

void main() {
  runApp(
    MultiProvider(
      providers: [
        Provider(create: (context) => ApiService()),
        Provider(create: (context) => UserService(context.read<ApiService>())),
      ],
      child: MyApp(),
    ),
  );
}

class ApiService {
  String fetchData() {
    return "Data from API";
  }
}

class UserService {
  final ApiService apiService;

  UserService(this.apiService);

  String getUserData() {
    return apiService.fetchData();
  }
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Provider Dependency Injection')),
        body: Center(
          child: Consumer<UserService>(
            builder: (context, userService, child) {
              return Text(userService.getUserData(), style: TextStyle(fontSize: 24));
            },
          ),
        ),
      ),
    );
  }
}
关键点:
  • MultiProvider :当你需要提供多个依赖项时,可以使用 MultiProvider。这里我们注入了两个服务:ApiServiceUserService
  • 依赖注入UserService 依赖于 ApiService,并且通过 context.read<ApiService>() 获取该服务。

4. 使用 FutureProviderStreamProvider

Provider 支持 FutureStream,你可以使用 FutureProvider 来异步加载数据,或使用 StreamProvider 来监听数据流。这对于异步操作(如网络请求或数据库查询)非常有用。

示例:使用 FutureProvider
dart 复制代码
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

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

class DataProvider with ChangeNotifier {
  Future<String> fetchData() async {
    await Future.delayed(Duration(seconds: 2));
    return "Hello from the Future!";
  }
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('FutureProvider Example')),
        body: Center(
          child: Consumer<DataProvider>(
            builder: (context, dataProvider, child) {
              return FutureProvider<String>(
                create: (_) => dataProvider.fetchData(),
                initialData: "Loading...",
                child: Builder(
                  builder: (context) {
                    String data = context.watch<String>();
                    return Text(data, style: TextStyle(fontSize: 24));
                  },
                ),
              );
            },
          ),
        ),
      ),
    );
  }
}
关键点:
  • FutureProviderFutureProvider 用来管理和提供一个异步操作(Future)的结果。你可以用它来在获取数据时显示加载状态。
  • 异步数据更新FutureProvider 会自动处理 Future 状态,提供初始数据并在数据加载完成后更新。

5. ProviderChangeNotifier 自动销毁资源

使用 ChangeNotifierProvider 时,可以确保在 Provider 不再使用时自动销毁其资源。通过设置 dispose 方法,可以确保当 Provider 不再被使用时自动清理资源,避免内存泄漏。

dart 复制代码
ChangeNotifierProvider(
  create: (context) => MyNotifier(),
  dispose: (context, notifier) => notifier.dispose(),
)

总结

Provider 在 Flutter 中非常强大,支持各种进阶用法。需要多加练习,特别是对于异步使用

相关推荐
前端之虎陈随易6 小时前
编程语言级别的Skill市场,AI Agent 的未来形态
前端·vue.js·人工智能·typescript·node.js
一路向北he6 小时前
字节钢铁军团--“提供情境,而非控制”
java·开发语言·前端
kyriewen6 小时前
豆包和千问同时关了智能体,我用它们搭的 3 个自动化全废了——迁移方案整理
前端·javascript·ai编程
前端一小卒7 小时前
我用 TypeScript 从零手写了一个 Claude Code,然后发现它的核心只有 30 行
前端·agent
铁皮饭盒7 小时前
用 Bun.cron 定时 7 月 7 日,为啥? 看图1
javascript
GitLqr7 小时前
Flutter 3.44 插件内置 Kotlin (KGP) 双向兼容适配指南
android·flutter·dart
大圣编程8 小时前
Python中continue语句的用法是什么?
开发语言·前端·python
yuhaiqiang8 小时前
随手 vibecoding 的浏览器插件已经 6000 多次下载,聊聊他的产品设计
前端·后端·面试
之歆9 小时前
Vue商品详情与放大镜组件
前端·javascript·vue.js
再吃一根胡萝卜9 小时前
如何把小米 MiMo 接入 CodeBuddy,打造私有 Agent
前端