Flutter 学习之旅 之 flutter 使用 Provider 实现简朴监听UI数据厘革/通知U ...

打印 上一主题 下一主题

主题 982|帖子 982|积分 2956

Flutter 学习之旅 之 flutter 使用 Provider 实现简朴监听UI数据厘革/通知UI刷新的简朴封装


目录
Flutter 学习之旅 之 flutter 使用 Provider 实现简朴监听UI数据厘革/通知UI刷新的简朴封装
一、简朴先容
二、flutter_native_splash
三、安装 provider
四、简朴案例实现
五、关键代码与阐明
六、在使用 provider 中的一些注意事项
1. 公道拆分状态
2. 使用 MultiProvider
3. 正确使用 Provider.of
4. 使用 Consumer 或 Selector
5. 避免过度使用 Provider
6. 管理生命周期
7. 避免内存走漏
8. 公道使用 notifyListeners
9. 调试和日志
10. 文档和注释


一、简朴先容

Flutter 是一款开源的 UI 软件开发工具包,由 Google 开发和维护。它允许开发者使用一套代码同时构建跨平台的应用程序,包罗移动设备(iOS 和 Android)、Web 和桌面平台(Windows、macOS 和 Linux)。
Flutter 使用 Dart 编程语言,它可以将代码编译为 ARM 或 Intel 机器代码以及 JavaScript,从而实现快速的性能。Flutter 提供了一个丰富的预置小部件库,开发者可以根据自己的需求机动地控制每个像素,从而创建自界说的、顺应性强的筹划,这些筹划在任何屏幕上都能出现出色的表面和感觉。

   在 Flutter 中举行 UI 的数据更新管理有多种方式,以下是一些常见的方法:
  

  • 1. 使用 setState 方法
  setState 是最简朴直接的方式,实用于简朴的状态厘革,如按钮点击计数、开关状态等。当状态发生厘革时,调用 setState 会触发整个组件的重新构建,但必要注意避免频繁调用,以免影响性能。
  

  • 2. 使用 StatefulWidget 和 InheritedWidget
  StatefulWidget 是具有状态的组件,InheritedWidget 用于在组件树中共享数据。当必要共享状态时,如主题、语言设置等,可以结合使用它们来实现局部刷新。
  

  • 3. 使用 GlobalKey
  GlobalKey 可以唯一标识元素,并提供对这些元素相关联的访问,比如 BuildContext 和 State。通过 GlobalKey 可以直接访问到必要局部刷新的组件的 State,并调用其 setState 方法来实现局部刷新。
  

  • 4. 使用 StreamBuilder
  StreamBuilder 是用于监听流(Stream)厘革的 widget,实用于处置惩罚异步数据流,如网络请求、实时数据等。当流中的数据发生厘革时,StreamBuilder 会根据新的数据重新构建其子树,从而实现局部刷新。
  

  • 5. 使用 Provider 和 ChangeNotifierProvider
  Provider 是一个流行的状态管理库,ChangeNotifierProvider 是其提供的一个用于管理状态的组件。通过在组件树中恰当地放置 ChangeNotifierProvider,可以在必要时更新状态,并通过状态的厘革来触发局部 UI 的刷新。
  

  • 6. 使用 ValueNotifier 和 ValueListenableBuilder
  ValueNotifier 是一个用于通知监听器值已更改的类,ValueListenableBuilder 是一个根据 ValueListenable 的当前值构建 widget 的组件。当 ValueNotifier 的值发生厘革时,ValueListenableBuilder 会根据新的值重新构建其子树,实现局部刷新。
  

  • 7. 使用第三方状态管理库
  除了 Flutter 自带的工具外,还可以使用第三方状态管理库,如 GetX。GetX 提供了简朴易用的状态管理方式,通过 GetBuilder 和 update 方法可以方便地实现 UI 的局部刷新。
  选择哪种方式取决于应用的具体需求和复杂水平。简朴的应用可以使用 setState 或 ValueNotifier,而复杂的应用则更得当使用 Provider 或第三方库。
  
二、flutter_native_splash

官网地址:provider | Flutter package
Flutter 中的 Provider 是一种流行且强大的状态管理解决方案。它通过 ChangeNotifier 和 Provider 组件,将状态与 UI 分离,实现高效的状态管理和 UI 更新。
   

  • 核心概念:Provider 使用 ChangeNotifier 来管理状态,当状态改变时,通过 notifyListeners() 通知 UI 更新。
  • 使用方式:通过 ChangeNotifierProvider 将状态提供给整个应用,使用 Provider.of<YourModel>(context) 或 Consumer<YourModel> 在 UI 中读取和更新状态。
  • 优点:代码布局清晰,状态管理简朴易懂,支持局部更新,减少不必要的 UI 重建。
  • 实用场景:实用于中到大型应用,尤其是必要跨页面共享状态的场景。
  Provider 是 Flutter 开发中推荐的状态管理方式之一,它结合了 Flutter 的响应式架构,使状态管理更加机动和高效。


三、安装 provider

1、直接运行命令: flutter pub add provider

2、大概在 pubspec.yaml 添加
  1. dependencies:
  2.   provider: ^6.1.2
复制代码


四、简朴案例实现

1、这里使用 Android Studio 举行创建 Flutter 项目

、创建一个 application 的 Flutter 项目

3、创建的工程布局如下

4、编写一个 provider


5、编写另一个 provider


6、编写一个 login界面


7、编写一个 home界面


8、在 main 中,添加 provider,添加界面导航,主要逻辑如下


9、连接设备,运行效果如下


五、关键代码与阐明

1、LoginProvider
  1. import 'package:flutter/material.dart';
  2. // 定义一个名为 LoginProvider 的类,它继承自 ChangeNotifier,用于管理登录相关的状态
  3. class LoginProvider with ChangeNotifier {
  4.   // 私有变量 _phoneNumber,用于存储用户输入的手机号
  5.   String _phoneNumber = '';
  6.   // 私有变量 _isAgreed,用于存储用户是否同意协议的状态
  7.   bool _isAgreed = false;
  8.   // 公开的 getter 方法,用于外部获取当前的手机号状态
  9.   String get phoneNumber => _phoneNumber;
  10.   // 公开的 getter 方法,用于外部获取当前的是否同意协议的状态
  11.   bool get isAgreed => _isAgreed;
  12.   // 更新手机号的方法
  13.   void updatePhoneNumber(String number) {
  14.     // 将传入的手机号赋值给私有变量 _phoneNumber
  15.     _phoneNumber = number;
  16.     // 调用 notifyListeners() 方法,通知所有监听该状态的组件,状态已经改变,需要重新构建
  17.     notifyListeners();
  18.   }
  19.   // 更新是否同意协议的方法
  20.   void updateAgreed(bool agreed) {
  21.     // 将传入的是否同意协议的状态赋值给私有变量 _isAgreed
  22.     _isAgreed = agreed;
  23.     // 调用 notifyListeners() 方法,通知所有监听该状态的组件,状态已经改变,需要重新构建
  24.     notifyListeners();
  25.   }
  26.   // 计算属性,用于判断是否满足使能登录按钮的条件
  27.   bool get isLoginEnabled {
  28.     // 当手机号不为空且用户已同意协议时,返回 true,表示登录按钮可点击
  29.     return _phoneNumber.isNotEmpty && _isAgreed;
  30.   }
  31. }
复制代码
  代码阐明
  

  • 类界说

    • class LoginProvider with ChangeNotifier:界说了一个名为 LoginProvider 的类,它继承自 ChangeNotifier。ChangeNotifier 是 Flutter 提供的一个类,用于管理状态厘革并通知监听者。

  • 私有变量

    • _phoneNumber 和 _isAgreed 是私有变量,用于存储用户输入的手机号和是否同意协议的状态。私有变量以 _ 开头,体现它们只能在类内部访问。

  • 公开的 getter 方法

    • phoneNumber 和 isAgreed 是公开的 getter 方法,用于外部组件获取当前的状态值。通过这些方法,其他组件可以读取状态,但不能直接修改。

  • 状态更新方法

    • updatePhoneNumber 和 updateAgreed 是用于更新状态的方法。当调用这些方法时,会更新对应的私有变量,并调用 notifyListeners() 方法通知所有监听该状态的组件,状态已经改变,必要重新构建。

  • 计算属性

    • isLoginEnabled 是一个计算属性,用于判断是否满足使能登录按钮的条件。只有当手机号不为空且用户已同意协议时,返回 true,体现登录按钮可点击。

  通过这些注释,你可以更清晰地理解 LoginProvider 的作用和实现方式。
  
2、UserProvider
  1. import 'package:flutter/material.dart';
  2. // 定义一个名为 UserProvider 的类,用于管理用户信息的状态。
  3. // 该类继承自 ChangeNotifier,以便在状态发生变化时通知监听者。
  4. class UserProvider with ChangeNotifier {
  5.   // 私有变量 _username,用于存储用户的用户名。
  6.   String _username = '';
  7.   // 私有变量 _age,用于存储用户的年龄。
  8.   int _age = 0;
  9.   // 公开的 getter 方法,用于外部获取当前的用户名状态。
  10.   // 通过这种方式,其他组件可以读取用户名,但不能直接修改。
  11.   String get username => _username;
  12.   // 公开的 getter 方法,用于外部获取当前的年龄状态。
  13.   // 通过这种方式,其他组件可以读取年龄,但不能直接修改。
  14.   int get age => _age;
  15.   // 更新用户名的方法。
  16.   // 当外部调用此方法并传入新的用户名时,会更新 _username 的值,
  17.   // 并通过 notifyListeners() 通知所有监听该状态的组件,状态已经改变,需要重新构建。
  18.   void updateUsername(String name) {
  19.     _username = name;
  20.     notifyListeners();
  21.   }
  22.   // 更新年龄的方法。
  23.   // 当外部调用此方法并传入新的年龄时,会更新 _age 的值,
  24.   // 并通过 notifyListeners() 通知所有监听该状态的组件,状态已经改变,需要重新构建。
  25.   void updateAge(int age) {
  26.     _age = age;
  27.     notifyListeners();
  28.   }
  29. }
复制代码
  代码阐明
  

  • 类界说

    • class UserProvider with ChangeNotifier:界说了一个名为 UserProvider 的类,它继承自 ChangeNotifier。ChangeNotifier 是 Flutter 提供的一个类,用于管理状态厘革并通知监听者。

  • 私有变量

    • _username 和 _age 是私有变量,用于存储用户的用户名和年岁。私有变量以 _ 开头,体现它们只能在类内部访问。

  • 公开的 getter 方法

    • username 和 age 是公开的 getter 方法,用于外部组件获取当前的状态值。通过这些方法,其他组件可以读取状态,但不能直接修改。

  • 状态更新方法

    • updateUsername 和 updateAge 是用于更新状态的方法。当调用这些方法时,会更新对应的私有变量,并调用 notifyListeners() 方法通知所有监听该状态的组件,状态已经改变,必要重新构建。

  通过这些注释,你可以更清晰地理解 UserProvider 的作用和实现方式。
  
3、LoginPage
  1. import 'package:flutter/material.dart';
  2. import 'package:provider/provider.dart';
  3. import 'package:test_ui_provider/page/home_page.dart';
  4. import 'package:test_ui_provider/provider/login_provider.dart';
  5. // 定义一个名为 LoginPage 的无状态组件,用于实现登录页面的 UI 和逻辑。
  6. class LoginPage extends StatelessWidget {
  7.   // 创建一个 TextEditingController 实例,用于控制手机号输入框的内容。
  8.   final TextEditingController _phoneNumberController = TextEditingController();
  9.   @override
  10.   Widget build(BuildContext context) {
  11.     // 使用 Scaffold 构建页面的基本结构,包括顶部导航栏和页面主体内容。
  12.     return Scaffold(
  13.       appBar: AppBar(
  14.         // 设置导航栏标题为 "Login Page"。
  15.         title: Text('Login Page'),
  16.       ),
  17.       body: Padding(
  18.         // 在页面主体内容周围添加 16.0 的内边距,以提供更好的视觉效果。
  19.         padding: const EdgeInsets.all(16.0),
  20.         child: Column(
  21.           // 使用 Column 垂直排列页面中的各个子组件。
  22.           children: [
  23.             // 创建一个文本输入框,用于用户输入手机号。
  24.             TextField(
  25.               controller: _phoneNumberController, // 将手机号输入框与 TextEditingController 绑定。
  26.               decoration: InputDecoration(labelText: 'Phone Number'), // 设置输入框的提示文本为 "Phone Number"。
  27.               onChanged: (value) {
  28.                 // 当用户输入手机号时,调用 LoginProvider 的 updatePhoneNumber 方法更新状态。
  29.                 // 使用 Provider.of 获取 LoginProvider 实例,并设置 listen: false,避免不必要的重建。
  30.                 Provider.of<LoginProvider>(context, listen: false)
  31.                     .updatePhoneNumber(value);
  32.               },
  33.             ),
  34.             // 创建一个复选框列表项,用于用户勾选同意协议。
  35.             CheckboxListTile(
  36.               title: Text('I agree to the terms and conditions'), // 设置复选框的标题为 "I agree to the terms and conditions"。
  37.               value: Provider.of<LoginProvider>(context).isAgreed, // 使用 Provider 获取当前的 isAgreed 状态值。
  38.               onChanged: (value) {
  39.                 // 当用户勾选或取消勾选复选框时,调用 LoginProvider 的 updateAgreed 方法更新状态。
  40.                 // 使用 Provider.of 获取 LoginProvider 实例,并设置 listen: false,避免不必要的重建。
  41.                 Provider.of<LoginProvider>(context, listen: false)
  42.                     .updateAgreed(value ?? false);
  43.               },
  44.             ),
  45.             // 使用 Consumer 监听 LoginProvider 的状态变化,并根据状态构建登录按钮。
  46.             Consumer<LoginProvider>(
  47.               builder: (context, provider, child) {
  48.                 // 根据 LoginProvider 的 isLoginEnabled 状态,决定登录按钮是否可点击。
  49.                 return ElevatedButton(
  50.                   onPressed: provider.isLoginEnabled ? () {
  51.                     // 如果满足登录条件,导航到 HomePage。
  52.                     Navigator.pushReplacement(
  53.                       context,
  54.                       MaterialPageRoute(builder: (context) => HomePage()),
  55.                     );
  56.                   } : null, // 如果不满足登录条件,按钮不可点击。
  57.                   child: Text('Login'), // 设置按钮文本为 "Login"。
  58.                 );
  59.               },
  60.             ),
  61.           ],
  62.         ),
  63.       ),
  64.     );
  65.   }
  66. }
复制代码
  代码阐明
  

  • 类界说

    • class LoginPage extends StatelessWidget:界说了一个无状态组件 LoginPage,用于实现登录页面的 UI 和逻辑。

  • TextEditingController

    • final TextEditingController _phoneNumberController = TextEditingController():创建一个 TextEditingController 实例,用于控制手机号输入框的内容。

  • Scaffold

    • 使用 Scaffold 构建页面的根本布局,包罗顶部导航栏和页面主体内容。

  • TextField

    • 创建一个文本输入框,用于用户输入手机号。
    • 使用 onChanged 回调函数,当用户输入手机号时,调用 LoginProvider 的 updatePhoneNumber 方法更新状态。

  • CheckboxListTile

    • 创建一个复选框列表项,用于用户勾选同意协议。
    • 使用 onChanged 回调函数,当用户勾选或取消勾选复选框时,调用 LoginProvider 的 updateAgreed 方法更新状态。

  • Consumer

    • 使用 Consumer 监听 LoginProvider 的状态厘革,并根据状态构建登录按钮。
    • 根据 LoginProvider 的 isLoginEnabled 状态,决定登录按钮是否可点击。

  • 导航

    • 假如满足登录条件,使用 Navigator.pushReplacement 跳转到 HomePage。

  通过这些注释,你可以更清晰地理解 LoginPage 的实现逻辑和代码布局。
  4、HomePage
  1. import 'package:flutter/material.dart';
  2. import 'package:provider/provider.dart';
  3. import 'package:test_ui_provider/provider/login_provider.dart';
  4. import 'package:test_ui_provider/provider/user_provider.dart';
  5. // 定义一个名为 HomePage 的无状态组件,用于实现主页的 UI 和逻辑。
  6. class HomePage extends StatelessWidget {
  7.   // 创建两个 TextEditingController 实例,分别用于控制用户名和年龄输入框的内容。
  8.   final TextEditingController _usernameController = TextEditingController();
  9.   final TextEditingController _ageController = TextEditingController();
  10.   @override
  11.   Widget build(BuildContext context) {
  12.     // 使用 Scaffold 构建页面的基本结构,包括顶部导航栏和页面主体内容。
  13.     return Scaffold(
  14.       appBar: AppBar(
  15.         // 设置导航栏标题为 "Home Page"。
  16.         title: Text('Home Page'),
  17.       ),
  18.       body: Center(
  19.         // 将页面主体内容居中显示。
  20.         child: Column(
  21.           // 使用 Column 垂直排列页面中的各个子组件,并将子组件居中对齐。
  22.           mainAxisAlignment: MainAxisAlignment.center,
  23.           children: [
  24.             // 显示欢迎信息。
  25.             Text('Welcome to the Home Page!'),
  26.             // 显示用户的手机号,通过 Provider 获取 LoginProvider 中的 phoneNumber 状态。
  27.             Text(
  28.               'Your Phone Number: ${Provider.of<LoginProvider>(context).phoneNumber}',
  29.             ),
  30.             // 显示用户的用户名,通过 Provider 获取 UserProvider 中的 username 状态。
  31.             Text(
  32.               'Your Username: ${Provider.of<UserProvider>(context).username}',
  33.             ),
  34.             // 显示用户的年龄,通过 Provider 获取 UserProvider 中的 age 状态。
  35.             Text(
  36.               'Your Age: ${Provider.of<UserProvider>(context).age}',
  37.             ),
  38.             // 创建一个文本输入框,用于用户输入用户名。
  39.             TextField(
  40.               controller: _usernameController, // 将用户名输入框与 TextEditingController 绑定。
  41.               decoration: InputDecoration(labelText: 'Username'), // 设置输入框的提示文本为 "Username"。
  42.               onChanged: (value) {
  43.                 // 当用户输入用户名时,调用 UserProvider 的 updateUsername 方法更新状态。
  44.                 // 使用 Provider.of 获取 UserProvider 实例,并设置 listen: false,避免不必要的重建。
  45.                 Provider.of<UserProvider>(context, listen: false)
  46.                     .updateUsername(value);
  47.               },
  48.             ),
  49.             // 创建一个文本输入框,用于用户输入年龄。
  50.             TextField(
  51.               controller: _ageController, // 将年龄输入框与 TextEditingController 绑定。
  52.               decoration: InputDecoration(labelText: 'Age'), // 设置输入框的提示文本为 "Age"。
  53.               onChanged: (value) {
  54.                 // 尝试将输入的字符串解析为整数。
  55.                 int? age = int.tryParse(value);
  56.                 if (age != null) {
  57.                   // 如果解析成功,调用 UserProvider 的 updateAge 方法更新状态。
  58.                   // 使用 Provider.of 获取 UserProvider 实例,并设置 listen: false,避免不必要的重建。
  59.                   Provider.of<UserProvider>(context, listen: false)
  60.                       .updateAge(age);
  61.                 }
  62.               },
  63.             ),
  64.             // 创建一个按钮,用于用户点击退出登录。
  65.             ElevatedButton(
  66.               onPressed: () {
  67.                 // 当用户点击按钮时,使用 Navigator.pop 返回到登录页面。
  68.                 Navigator.pop(context);
  69.               },
  70.               child: Text('Logout'), // 设置按钮文本为 "Logout"。
  71.             ),
  72.           ],
  73.         ),
  74.       ),
  75.     );
  76.   }
  77. }
复制代码
  代码阐明
  

  • 类界说

    • class HomePage extends StatelessWidget:界说了一个无状态组件 HomePage,用于实现主页的 UI 和逻辑。

  • TextEditingController

    • final TextEditingController _usernameController = TextEditingController() 和 final TextEditingController _ageController = TextEditingController():创建两个 TextEditingController 实例,分别用于控制用户名和年岁输入框的内容。

  • Scaffold

    • 使用 Scaffold 构建页面的根本布局,包罗顶部导航栏和页面主体内容。

  • Text

    • 使用 Text 组件体现用户的手机号、用户名和年岁。通过 Provider.of<roviderClass>(context) 获取对应的状态。

  • TextField

    • 创建两个文本输入框,分别用于用户输入用户名和年岁。
    • 使用 onChanged 回调函数,当用户输入内容时,调用 UserProvider 的 updateUsername 和 updateAge 方法更新状态。

  • ElevatedButton

    • 创建一个按钮,用于用户点击退出登录。
    • 使用 Navigator.pop 返回到登录页面。

  通过这些注释,你可以更清晰地理解 HomePage 的实现逻辑和代码布局。
  5、main
  1. import 'package:flutter/material.dart';
  2. import 'package:provider/provider.dart';
  3. import 'package:test_ui_provider/page/home_page.dart';
  4. import 'package:test_ui_provider/page/login_page.dart';
  5. import 'package:test_ui_provider/provider/login_provider.dart';
  6. import 'package:test_ui_provider/provider/user_provider.dart';
  7. void main() {
  8.   // 程序的入口点,启动 Flutter 应用。
  9.   runApp(
  10.     // 使用 MultiProvider 来同时提供多个状态管理器(Provider)。
  11.     // MultiProvider 允许在一个地方集中管理多个状态,便于在应用的不同部分共享状态。
  12.     MultiProvider(
  13.       providers: [
  14.         // 创建并提供一个 LoginProvider 实例,用于管理登录相关的状态。
  15.         ChangeNotifierProvider(create: (_) => LoginProvider()),
  16.         // 创建并提供一个 UserProvider 实例,用于管理用户信息相关的状态。
  17.         ChangeNotifierProvider(create: (_) => UserProvider()),
  18.       ],
  19.       child: MyApp(), // MyApp 是应用的根组件,负责构建整个应用的路由和布局。
  20.     ),
  21.   );
  22. }
  23. // 定义一个名为 MyApp 的无状态组件,它是应用的根组件。
  24. class MyApp extends StatelessWidget {
  25.   @override
  26.   Widget build(BuildContext context) {
  27.     // 使用 MaterialApp 构建整个应用,它提供了导航、主题等基础功能。
  28.     return MaterialApp(
  29.       // 设置应用的初始路由为 '/',对应登录页面。
  30.       initialRoute: '/',
  31.       // 定义应用的路由表,指定不同路由对应的页面组件。
  32.       routes: {
  33.         '/': (context) => LoginPage(), // 登录页面的路由,路径为 '/'。
  34.         '/home': (context) => HomePage(), // 主页的路由,路径为 '/home'。
  35.       },
  36.     );
  37.   }
  38. }
复制代码
  代码阐明
  

  • 程序入口点

    • void main():程序的入口点,启动 Flutter 应用。

  • MultiProvider

    • MultiProvider:用于同时提供多个状态管理器(Provider)。它允许在一个地方集中管理多个状态,便于在应用的差别部分共享状态。

  • ChangeNotifierProvider

    • ChangeNotifierProvider(create: (_) => LoginProvider()):创建并提供一个 LoginProvider 实例,用于管理登录相关的状态。
    • ChangeNotifierProvider(create: (_) => UserProvider()):创建并提供一个 UserProvider 实例,用于管理用户信息相关的状态。

  • MyApp

    • class MyApp extends StatelessWidget:界说了一个无状态组件 MyApp,它是应用的根组件,负责构建整个应用的路由和布局。

  • MaterialApp

    • MaterialApp:用于构建整个应用,它提供了导航、主题等底子功能。
    • initialRoute: '/':设置应用的初始路由为 '/',对应登录页面。
    • routes:界说应用的路由表,指定差别路由对应的页面组件。

      • '/':登录页面的路由。
      • '/home':主页的路由。


  通过这些注释,你可以更清晰地理解主程序代码的布局和功能。
  六、在使用 provider 中的一些注意事项

在使用 Flutter 的 Provider 举行状态管理时,以下是一些重要的注意事项和最佳实践,可以资助你更高效地管理和维护应用的状态:
1. 公道拆分状态

   

  • 单一职责原则:每个 Provider 应该只管理一个独立的状态模块。例如,LoginProvider 只管理登录相关的状态,UserProvider 只管理用户信息相关的状态。
  • 避免臃肿的 Provider:不要将所有状态都放在一个 Provider 中,如许会导致代码难以维护和扩展。
  2. 使用 MultiProvider

   

  • 集中管理多个 Provider:假如必要同时使用多个 Provider,建议在应用的顶层使用 MultiProvider 来集中管理。如许可以避免在多个地方重复提供雷同的 Provider。
  • 示例
    1. runApp(
    2.   MultiProvider(
    3.     providers: [
    4.       ChangeNotifierProvider(create: (_) => LoginProvider()),
    5.       ChangeNotifierProvider(create: (_) => UserProvider()),
    6.     ],
    7.     child: MyApp(),
    8.   ),
    9. );
    复制代码
  3. 正确使用 Provider.of

   

  • 获取状态:使用 Provider.of<YourProvider>(context) 获取状态。
  • 更新状态:更新状态时,使用 Provider.of<YourProvider>(context, listen: false)。设置 listen: false 可以避免不必要的 UI 重建。
  • 示例
    1. // 获取状态
    2. String phoneNumber = Provider.of<LoginProvider>(context).phoneNumber;
    3. // 更新状态
    4. Provider.of<LoginProvider>(context, listen: false).updatePhoneNumber('1234567890');
    复制代码
  4. 使用 Consumer 或 Selector

   

  • 局部更新:假如只必要根据部分状态更新 UI,可以使用 Consumer 或 Selector。Consumer 会监听整个 Provider 的状态厘革,而 Selector 可以选择性地监听特定的状态厘革。
  • 示例
    1. // 使用 Consumer
    2. Consumer<LoginProvider>(
    3.   builder: (context, provider, child) {
    4.     return ElevatedButton(
    5.       onPressed: provider.isLoginEnabled ? () {} : null,
    6.       child: Text('Login'),
    7.     );
    8.   },
    9. );
    10. // 使用 Selector
    11. Selector<LoginProvider, bool>(
    12.   selector: (_, provider) => provider.isLoginEnabled,
    13.   builder: (context, isLoginEnabled, child) {
    14.     return ElevatedButton(
    15.       onPressed: isLoginEnabled ? () {} : null,
    16.       child: Text('Login'),
    17.     );
    18.   },
    19. );
    复制代码
  5. 避免过度使用 Provider

   

  • 局部状态:对于一些简朴的局部状态(如按钮的点击状态),可以使用 StatefulWidget 或 ValueNotifier,而不是 Provider。
  • 示例
    1. class MyButton extends StatefulWidget {
    2.   @override
    3.   _MyButtonState createState() => _MyButtonState();
    4. }
    5. class _MyButtonState extends State<MyButton> {
    6.   bool _isPressed = false;
    7.   @override
    8.   Widget build(BuildContext context) {
    9.     return ElevatedButton(
    10.       onPressed: () {
    11.         setState(() {
    12.           _isPressed = !_isPressed;
    13.         });
    14.       },
    15.       child: Text(_isPressed ? 'Pressed' : 'Not Pressed'),
    16.     );
    17.   }
    18. }
    复制代码
  6. 管理生命周期

   

  • 清理资源:假如 Provider 中有必要清理的资源(如定时器、订阅等),确保在 dispose 方法中举行清理。
  • 示例
    1. class MyProvider with ChangeNotifier {
    2.   Timer? _timer;
    3.   @override
    4.   void dispose() {
    5.     _timer?.cancel();
    6.     super.dispose();
    7.   }
    8. }
    复制代码
  7. 避免内存走漏

   

  • 监听器管理:确保在不必要时移除监听器,避免内存走漏。
  • 示例
    1. class MyWidget extends StatelessWidget {
    2.   @override
    3.   Widget build(BuildContext context) {
    4.     return Consumer<MyProvider>(
    5.       builder: (context, provider, child) {
    6.         return ElevatedButton(
    7.           onPressed: () {
    8.             provider.dispose(); // 确保在不需要时清理资源
    9.           },
    10.           child: Text('Dispose Provider'),
    11.         );
    12.       },
    13.     );
    14.   }
    15. }
    复制代码
  8. 公道使用 notifyListeners

   

  • 避免过度调用:只在状态真正发生厘革时调用 notifyListeners(),避免不必要的 UI 重建。
  • 示例
    1. class MyProvider with ChangeNotifier {
    2.   int _count = 0;
    3.   void increment() {
    4.     _count++;
    5.     notifyListeners(); // 只在状态变化时调用
    6.   }
    7. }
    复制代码
  9. 调试和日志

   

  • 添加日志:在 notifyListeners() 调用前后添加日志,资助调试状态厘革。
  • 示例
    1. class MyProvider with ChangeNotifier {
    2.   int _count = 0;
    3.   void increment() {
    4.     print('Incrementing count from $_count');
    5.     _count++;
    6.     notifyListeners();
    7.     print('Count is now $_count');
    8.   }
    9. }
    复制代码
  10. 文档和注释



  •        清晰的文档:为每个 Provider 和状态管理逻辑添加清晰的注释和文档,便于团队成员理解和维护代码。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

泉缘泉

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表