欢迎访问移动开发之家(rcyd.net),关注移动开发教程。移动开发之家  移动开发问答|  每日更新
页面位置 : > > > 内容正文

Flutter使用Provider进行状态管理的实现,

来源: 开发者 投稿于  被查看 49787 次 评论:87

Flutter使用Provider进行状态管理的实现,


目录
  • 一、使用Provider进行状态管理的基本用法
    • 1.添加provider依赖
    • 2.创建一个数据模型
    • 3.在应用中提供模型
    • 4.使用Consumer或Provider.of读取和显示数据
  • 二、管理多个不同的状态
    • 1.创建多个模型
    • 2.同时管理多个状态
  • 三、异步获取状态

    一、使用Provider进行状态管理的基本用法

    Provider是Flutter中一个非常流行的状态管理工具,它可以帮助开发者更有效地管理Widget树中的数据。Provider的核心思想是将数据模型放置在Widget树中可以被多个子Widget访问的地方,而不必通过构造函数手动传递。

    1.添加provider依赖

    dependencies:
      flutter:
        sdk: flutter
      provider: ^6.0.0  

    2.创建一个数据模型

    import 'package:flutter/material.dart';
    
    class CounterModel with ChangeNotifier {
      int _count = 0;
    
      int get count => _count;
    
      void increment() {
        _count++;
        notifyListeners(); // 通知监听者数据改变
      }
    }

    3.在应用中提供模型

    在你的应用中,你需要在一个合适的位置(如MaterialApp的上方)使用ChangeNotifierProvider来创建并提供CounterModel的实例。

    import 'package:provider/provider.dart';
    
    void main() {
      runApp(
        // 注意:ChangeNotifierProvider要包装在MaterialApp之外
        ChangeNotifierProvider(
          create: (context) => CounterModel(),
          child: MyApp(),
        ),
      );
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: HomeScreen(),
        );
      }
    }

    4.使用Consumer或Provider.of读取和显示数据

    在你的HomeScreen中,你可以使用ConsumerProvider.of来读取CounterModel的数据,并构建UI。

    class HomeScreen extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('Provider Example'),
          ),
          body: Center(
            // 使用Consumer来监听CounterModel
            child: Consumer<CounterModel>(
              builder: (context, counter, child) => Text('${counter.count}'),
            ),
          ),
          floatingActionButton: FloatingActionButton(
            onPressed: () {
              // 不需要监听改变时,可以直接使用Provider.of来访问模型
              Provider.of<CounterModel>(context, listen: false).increment();
            },
            child: Icon(Icons.add),
          ),
        );
      }
    }

    当你点击浮动按钮时,increment方法会被调用,CounterModel中的计数器会增加,并通过notifyListeners通知Consumer重新构建,这样UI上显示的数字就会更新。

    注意:

    • 使用Provider.of(context)时,如果你不需要监听变化,可以设置listen: false,这样可以提高性能。
    • 当模型更新时,只有通过Consumer或者Provider.of(context)(并且listen设置为true)获取模型的Widget才会重新构建。

    二、管理多个不同的状态

    如果你有多个不同的状态需要管理,你通常会为每种状态创建不同的模型。每个模型专注于管理一组相关的状态数据和行为。这样可以帮助你保持代码的清晰和分离关注点,使得每个模型都保持简单和专注。

    但是,如果你的状态数据非常紧密相关,并且它们通常一起改变,那么将它们放在同一个模型中也是有意义的。

    1.创建多个模型

    计数器模型

    class CounterModel with ChangeNotifier {
      int _count = 0;
    
      int get count => _count;
    
      void increment() {
        _count++;
        notifyListeners();
      }
    }

    主题色彩模型

    class ThemeModel with ChangeNotifier {
      ThemeData _themeData = ThemeData.light();
    
      ThemeData get themeData => _themeData;
    
      void toggleTheme() {
        _themeData = _themeData == ThemeData.light() ? ThemeData.dark() : ThemeData.light();
        notifyListeners();
      }
    }

    2.同时管理多个状态

    在你的应用中,你可以使用MultiProvider来同时提供多个模型:

    void main() {
      runApp(
        MultiProvider(
          providers: [
            ChangeNotifierProvider(create: (context) => CounterModel()),
            ChangeNotifierProvider(create: (context) => ThemeModel()),
          ],
          child: MyApp(),
        ),
      );
    }

    你现在可以根据ThemeModel提供的主题数据来构建你的应用程序:

    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Consumer<ThemeModel>(
          builder: (context, themeModel, child) {
            return MaterialApp(
              theme: themeModel.themeData,
              home: HomeScreen(),
            );
          },
        );
      }
    }

    这样,你就可以在HomeScreen或者其他任何Widget中分别访问和操作CounterModelThemeModel了。通过这种方式,你可以将应用的不同部分的状态管理分离开来,从而使你的代码更加模块化和可维护。

    三、异步获取状态

    有时,我们不想在模型内部中直接管理状态,而是每次修改SharedPreferences中的缓存数据,以及直接从SharedPreferences获取状态。更进一步,比如异步从网络获取状态,也是类似的。

    比如,我们要管理一个订阅状态。

    import 'package:flutter/material.dart';
    import 'package:shared_preferences/shared_preferences.dart';
    
    class SubscriptionStatusModel extends ChangeNotifier {
    
      // 订阅状态的异步读取方法
      Future<bool> get isSubscribed async {
        final prefs = await SharedPreferences.getInstance();
        return prefs.getBool('isSubscribeValid') ?? false;
      }
    
      // 更新SharedPreferences中的订阅状态
      Future<void> updateSubscriptionStatus(bool newStatus) async {
        final prefs = await SharedPreferences.getInstance();
        await prefs.setBool('isSubscribeValid', newStatus);
        notifyListeners();  // 通知监听器可能有变化
      }
    
    }

    在上面的代码中,isSubscribed 现在是一个异步 getter,每次调用时都会从 SharedPreferences 中读取订阅状态。updateSubscriptionStatus 方法现在会将新状态写入 SharedPreferences 并通知监听器。

    这样修改后,你就需要在UI中相应地处理Future。例如,如果你在一个widget中使用这个模型,你可能需要使用 FutureBuilder

    FutureBuilder<bool>(
      future: provider.isSubscribed, // 假设` provider `是你的SubscriptionStatusModel实例
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          // 等待数据时返回加载指示器
          return CircularProgressIndicator();
        } else if (snapshot.hasError) {
          // 处理错误情况
          return Text('Error: ${snapshot.error}');
        } else {
          // 使用订阅状态来构建widget
          bool isSubscribed = snapshot.data ?? false;
          return Text(isSubscribed ? 'Subscribed' : 'Not subscribed');
        }
      },
    )

    实际用例:

    Stack(
      alignment: Alignment.center,
      children: [
        CustomScrollView(
           // ...
        ),
        Consumer<SubscriptionStatusModel>(builder: (context, provider, child) {
          return FutureBuilder<bool>(
            future: provider.isSubscribed,  
            builder: (context, snapshot) {
              if (snapshot.connectionState == ConnectionState.waiting) {
                // 等待数据时返回加载指示器
                // return CircularProgressIndicator();
                return SizedBox.shrink();
              } else if (snapshot.hasError) {
                // 处理错误情况
                // return Text('Error: ${snapshot.error}');
                return SizedBox.shrink();
              } else {
                // 使用订阅状态来构建widget
                bool isSubscribed = snapshot.data ?? false;
                return Visibility(
                  visible: !isSubscribed,
                  child: Positioned(
                    left: 0,
                    right: 0,
                    bottom: 16,
                    child: _subscribeButton(),
                  ),
                );
              }
            },
          );
        }),
      ],
    ),

    到此这篇关于Flutter使用Provider进行状态管理的实现的文章就介绍到这了,更多相关Flutter Provider状态管理内容请搜索3672js教程以前的文章或继续浏览下面的相关文章希望大家以后多多支持3672js教程! 

    您可能感兴趣的文章:
    • Flutter状态管理Provider示例解析
    • flutter自定义InheritedProvider实现状态管理详解
    • Flutter状态管理Provider的使用示例详解
    • flutter状态管理Provider的使用学习

    用户评论