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 中非常强大,支持各种进阶用法。需要多加练习,特别是对于异步使用

相关推荐
m0_748233881 分钟前
【学一点儿前端】本地或jenkins打包报错:getaddrinfo ENOTFOUND registry.nlark.com
前端·servlet·jenkins
摸鲨鱼的脚2 分钟前
Vue导出报表功能【动态表头+动态列】
前端·javascript·vue.js
易和安15 分钟前
JS进阶DAY5|JS执行机制
开发语言·javascript·ecmascript
海上彼尚18 分钟前
npm、yarn、pnpm三者的异同
前端·npm·node.js
余生H19 分钟前
前端的 Python 入门指南(六):调试方式和技巧对比
开发语言·前端·javascript·python
m0_7482370523 分钟前
前端报错npm ERR cb() never called问题
前端·npm·node.js
818源码资源站34 分钟前
Ripro V5日主题 v8.3 开心授权版 wordpress主题虚拟资源下载站首选主题模板
前端
低代码布道师40 分钟前
第二篇:脚手架搭建 — React 和 Express 的搭建
前端·react.js·express
前端熊猫43 分钟前
React Router 6的学习
javascript·学习·react.js
m0_748238781 小时前
前端文件预览整合(一)
前端·状态模式