在 Flutter(以及 Dart)中,`as`、`show` 和 `hide` 是用于 `import` 语句的关键字,帮助开发者管理命名空间和导入的符号。

Flutter开发者必备面试问题与答案04

Flutter开发者必备面试问题与答案04

视频

前言

原文 Flutter 完整面试问题及答案04

本文是 flutter 面试问题的第四讲,高频问答 10 题。

正文

31. as 、show 和 hide 在 import 语句中的区别是什么?

在 Flutter(以及 Dart)中,asshowhide 是用于 import 语句的关键字,帮助开发者管理命名空间和导入的符号。下面是它们的区别和使用场景:

  1. as
  • 功能:用于为导入的库提供一个别名。
  • 使用场景
    • 当你想要避免命名冲突时,可以使用 as 为导入的库指定一个别名。
    • 在使用大型库时,使用别名可以让代码更清晰。

示例:

import 'package:flutter/material.dart' as myMaterial;

void main() {
  runApp(myMaterial.MaterialApp(
    home: myMaterial.Scaffold(
      appBar: myMaterial.AppBar(title: myMaterial.Text('Hello')),
      body: myMaterial.Center(child: myMaterial.Text('Hello World')),
    ),
  ));
}
  1. show
  • 功能:用于仅导入库中的特定符号,避免导入整个库。
  • 使用场景
    • 当你只需要库中的某几个类或函数时,使用 show 可以减少命名空间的混乱并提高代码的可读性。

示例:

import 'package:flutter/material.dart' show Text, Scaffold;

void main() {
  runApp(MaterialApp(
    home: Scaffold(
      appBar: AppBar(title: Text('Hello')),
      body: Center(child: Text('Hello World')),
    ),
  ));
}
  1. hide
  • 功能:用于导入库中的所有符号,但排除特定的符号。
  • 使用场景
    • 当你希望导入整个库,但不想使用某些特定的类或函数时,可以使用 hide

示例:

import 'package:flutter/material.dart' hide Text;

void main() {
  runApp(MaterialApp(
    home: Scaffold(
      appBar: AppBar(title: Text('Hello')), // 使用 Text 类会报错,因为它被隐藏
      body: Center(child: Text('Hello World')), // 这会报错
    ),
  ));
}
  • as:为导入的库设置别名,避免命名冲突。
  • show:仅导入库中的特定符号,提高代码的清晰度。
  • hide:导入库中的所有符号,但排除特定符号,控制命名空间。

根据具体的需求选择适合的导入方式,可以使代码更加整洁、可读和易于维护。


32. TextEditingController 的作用是什么?

在 Flutter 中,TextEditingController 是一个用于管理文本输入的控制器。它主要用于处理 TextFieldTextFormField 的文本输入,提供了一种方式来读取、修改和清空文本内容。以下是 TextEditingController 的主要作用和使用场景:

主要作用

  • 获取文本内容
    • 通过 TextEditingController,你可以方便地获取用户在 TextField 中输入的文本内容。
  • 更新文本内容
    • 你可以使用 TextEditingController 来动态更新 TextField 中的文本。例如,可以在某些事件发生时(如按钮点击)更新文本。
  • 监听文本变化
    • 通过 TextEditingController,你可以添加监听器来监控文本的变化,适用于需要实时处理输入的场景。
  • 清空文本
    • 可以通过控制器轻松地清空 TextField 中的文本内容。

使用场景

  • 表单输入:在表单中获取用户输入的信息,如用户名、密码等。
  • 搜索框:在搜索功能中实时获取用户输入的搜索关键词。
  • 动态更新:在用户输入时,实时更新其他 UI 元素的内容或状态。

示例

以下是一个简单的示例,展示如何使用 TextEditingController

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final TextEditingController _controller = TextEditingController();

  void _showInput() {
    final inputText = _controller.text; // 获取输入文本
    showDialog(
      context: context,
      builder: (context) {
        return AlertDialog(
          content: Text('You entered: $inputText'),
          actions: [
            TextButton(
              onPressed: () {
                Navigator.of(context).pop();
              },
              child: Text('OK'),
            ),
          ],
        );
      },
    );
  }

  @override
  void dispose() {
    _controller.dispose(); // 释放控制器资源
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('TextEditingController Example')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            TextField(
              controller: _controller, // 设置控制器
              decoration: InputDecoration(labelText: 'Enter something'),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: _showInput,
              child: Text('Show Input'),
            ),
          ],
        ),
      ),
    );
  }
}

TextEditingController 是在 Flutter 中处理文本输入的强大工具,能够帮助你获取、更新、监听和清空文本内容。它在表单、搜索框和动态输入等场景中非常实用。确保在不再需要控制器时调用 dispose() 方法来释放资源。


33. 为什么我们在 Listview 中使用 Reverse 属性?

在 Flutter 中,使用 ListViewreverse 属性可以让列表的滚动方向反转,即从底部开始向顶部滚动。这在某些特定的场景中非常有用,以下是一些常见的使用场景及其原因:

使用场景

  • 聊天应用
    • 在聊天应用中,通常希望最新的消息显示在底部,用户可以向上滚动查看更早的消息。使用 reverse: true 可以使得列表从底部开始滚动,以便用户能够直接看到最新的消息。
  • 时间线或动态列表
    • 类似于社交媒体应用,最新的动态(如评论、点赞)希望在列表的底部,而用户可以向上滚动查看过往的动态。设置 reverse 属性可以实现这一效果。
  • 增强用户体验
    • 通过将列表反转,可以提高用户的交互体验,特别是在需要频繁查看最新内容的场景下,用户无需滚动到底部就能看到新内容。

示例

以下是一个使用 reverse 属性的简单示例:

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('ListView Reverse Example')),
        body: ListView.builder(
          reverse: true, // 反转列表
          itemCount: 20,
          itemBuilder: (context, index) {
            return ListTile(
              title: Text('Item ${index + 1}'),
            );
          },
        ),
      ),
    );
  }
}

使用 ListViewreverse 属性可以在需要从底部开始显示内容的场景中提高用户体验,尤其是在聊天应用和动态列表中。这种反向滚动的布局方式使得用户可以更方便地查看最新信息,而无需频繁滚动。


34. 模态对话框和持久底部抽屉之间的区别是什么?

在 Flutter 中,模态对话框(Modal Dialog)持久底部抽屉(Persistent Bottom Sheet) 是两种不同的用户界面元素,它们在使用场景、外观和交互方式上有明显的区别。以下是它们的主要区别以及示例说明。

主要区别

  • 模态对话框(Modal Dialog)
    • 定义:模态对话框是一个覆盖在应用界面之上的弹出窗口,阻止用户与应用的其他部分进行交互,直到关闭对话框。
    • 使用场景:通常用于需要用户确认或输入信息的场景,例如确认删除、输入密码等。
    • 外观:通常是一个居中显示的方框,有标题和内容,用户需要采取行动(例如点击按钮)才能关闭它。
  • 持久底部抽屉(Persistent Bottom Sheet)
    • 定义:持久底部抽屉是从屏幕底部滑出的面板,可以与用户的主要内容部分同时显示,允许用户与两者交互。
    • 使用场景:适合于提供额外选项或操作的场景,比如显示选项列表、附加信息或操作按钮,而不阻止用户与背景内容的交互。
    • 外观:通常是一个半透明的面板,从底部滑出,用户可以通过向下滑动或点击背景来关闭它。

示例

模态对话框示例

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Modal Dialog Example')),
        body: Center(
          child: ElevatedButton(
            onPressed: () {
              showDialog(
                context: context,
                builder: (context) {
                  return AlertDialog(
                    title: Text('Confirm Action'),
                    content: Text('Are you sure you want to proceed?'),
                    actions: [
                      TextButton(
                        onPressed: () {
                          Navigator.of(context).pop(); // 关闭对话框
                        },
                        child: Text('Cancel'),
                      ),
                      TextButton(
                        onPressed: () {
                          // 执行确认操作
                          Navigator.of(context).pop();
                        },
                        child: Text('OK'),
                      ),
                    ],
                  );
                },
              );
            },
            child: Text('Show Modal Dialog'),
          ),
        ),
      ),
    );
  }
}

持久底部抽屉示例

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Persistent Bottom Sheet Example')),
        body: Center(
          child: ElevatedButton(
            onPressed: () {
              showModalBottomSheet(
                context: context,
                builder: (context) {
                  return Container(
                    height: 200,
                    child: Center(
                      child: Column(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: [
                          Text('Persistent Bottom Sheet'),
                          ElevatedButton(
                            onPressed: () {
                              Navigator.of(context).pop(); // 关闭底部抽屉
                            },
                            child: Text('Close'),
                          ),
                        ],
                      ),
                    ),
                  );
                },
              );
            },
            child: Text('Show Bottom Sheet'),
          ),
        ),
      ),
    );
  }
}
  • 模态对话框:适用于需要用户确认或输入的场景,阻止与其他界面的交互,通常用于重要的操作。
  • 持久底部抽屉:适合提供额外选项或信息,同时允许用户与背景内容交互,通常用于辅助操作。

根据具体的用户交互需求选择合适的组件,可以提升应用的用户体验和可用性。


35. Inherited Widget 与 Provider 有何不同?

在 Flutter 中,InheritedWidgetProvider 都是用于在小部件树中传递数据的机制,但它们在使用方式、复杂性和功能上存在一些重要的区别。以下是它们的主要不同点:

定义与目的

  • InheritedWidget
    • 是 Flutter 框架提供的基础类,允许在小部件树中共享数据。
    • 主要用于在小部件树中向下传递数据,适合于简单的状态管理。
    • 一般需要手动重建依赖于它的子小部件。
  • Provider
    • 是一个包(provider),基于 InheritedWidget 构建的更高级别的状态管理解决方案。
    • 提供了更简洁和强大的 API,使状态管理变得更容易和灵活。
    • 自动处理依赖关系的重建,简化了状态管理的流程。

使用复杂性

  • InheritedWidget
    • 使用相对复杂,需要手动实现状态的变化和通知。
    • 通常需要创建一个自定义的 InheritedWidget 类,管理状态并在状态变化时调用 notifyListeners()
  • Provider
    • 使用简便,提供了一种声明式的方式来管理和获取状态。
    • 不需要手动实现 InheritedWidget,可以直接使用 ChangeNotifierChangeNotifierProvider 来管理状态。

性能

  • InheritedWidget
    • 需要手动管理依赖关系,可能导致不必要的重建,尤其是在树中有多个依赖于同一数据的子小部件时。
  • Provider
    • 提供了更好的性能优化,自动处理依赖关系的重建。只有在相关数据变化时,依赖于该数据的小部件才会重建。

示例

使用 InheritedWidget 示例

import 'package:flutter/material.dart';

class MyInheritedWidget extends InheritedWidget {
  final int data;

  MyInheritedWidget({Key? key, required this.data, required Widget child})
      : super(key: key, child: child);

  static MyInheritedWidget? of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<MyInheritedWidget>();
  }

  @override
  bool updateShouldNotify(MyInheritedWidget oldWidget) {
    return oldWidget.data != data;
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MyInheritedWidget(
      data: 42,
      child: Scaffold(
        appBar: AppBar(title: Text('InheritedWidget Example')),
        body: Center(
          child: Text('Data: ${MyInheritedWidget.of(context)!.data}'),
        ),
      ),
    );
  }
}

void main() {
  runApp(MaterialApp(home: MyHomePage()));
}

使用 Provider 示例

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

class MyModel with ChangeNotifier {
  int _data = 42;

  int get data => _data;

  void updateData(int newData) {
    _data = newData;
    notifyListeners(); // 通知依赖的子小部件重建
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (context) => MyModel(),
      child: Scaffold(
        appBar: AppBar(title: Text('Provider Example')),
        body: Center(
          child: Consumer<MyModel>(
            builder: (context, model, child) {
              return Text('Data: ${model.data}');
            },
          ),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            context.read<MyModel>().updateData(100); // 更新数据
          },
          child: Icon(Icons.update),
        ),
      ),
    );
  }
}

void main() {
  runApp(MaterialApp(home: MyHomePage()));
}
  • InheritedWidget:适合简单的状态管理,使用较为底层,需要手动实现状态和通知。
  • Provider:基于 InheritedWidget,提供更高级和易用的 API,适合中大型应用中的状态管理。

选择使用哪种方式,通常取决于你的应用复杂度和状态管理的需求。对于大多数应用来说,Provider 是推荐的选择,因为它能够简化状态管理并提高代码的可读性。


36. UnmodifiableListView 是什么?

在 Flutter 中,UnmodifiableListView 是一个类,提供了一种不可修改的列表视图。它是 dart:collection 库的一部分,用于封装一个可变的 List,并确保该列表在创建后无法更改。这意味着你不能添加、删除或修改列表中的元素。

主要特点

  • 不可修改
    • 一旦创建,UnmodifiableListView 中的元素不能被修改。任何尝试修改操作(如添加、删除或更新元素)都会抛出异常。
  • 适用于暴露内部状态
    • 当你想要暴露一个列表给外部,但又不希望外部代码能够修改这个列表时,可以使用 UnmodifiableListView。这提供了一种安全的方式来共享数据。
  • 视图的同步
    • UnmodifiableListView 是对底层可变列表的视图。如果底层列表发生变化,UnmodifiableListView 也会反映这些变化,但外部不能改变它。

使用场景

  • 数据保护:在提供 API 或数据类时,确保外部无法直接修改内部状态。
  • 返回列表:当返回列表时,希望保持列表不变,可以使用 UnmodifiableListView

示例

以下是一个简单的示例,展示如何使用 UnmodifiableListView

import 'package:flutter/material.dart';
import 'dart:collection';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  final List<String> _items = ['Apple', 'Banana', 'Cherry'];

  @override
  Widget build(BuildContext context) {
    // 使用 UnmodifiableListView 包装可变列表
    final unmodifiableList = UnmodifiableListView(_items);

    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('UnmodifiableListView Example')),
        body: ListView.builder(
          itemCount: unmodifiableList.length,
          itemBuilder: (context, index) {
            return ListTile(
              title: Text(unmodifiableList[index]),
            );
          },
        ),
      ),
    );
  }
}

注意事项

  • 使用 UnmodifiableListView 时,确保底层列表在需要的情况下保持不变,或者在必要时使用其他方式来管理列表的状态。
  • 如果需要一个可以修改的列表,应该使用普通的 List,而不是 UnmodifiableListView

UnmodifiableListView 提供了一种安全的方式来共享列表数据,防止外部代码对列表进行修改。这在需要保护内部状态的场景中特别有用。


37. 运算符 ?? 和 ?. 之间的区别

在 Flutter(以及 Dart)中,???. 是两种不同的运算符,它们在处理 null 值时的行为有所不同。以下是它们的主要区别和使用场景:

1. ?? 运算符

  • 作用?? 是 null 合并运算符,用于提供一个默认值。当左侧的表达式为 null 时,返回右侧的值;否则,返回左侧的值。
  • 使用场景:常用于处理可能为 null 的值,并为其提供一个后备值。

示例:

void main() {
  String? name;
  String displayName = name ?? 'Guest'; // name 为 null,返回 'Guest'
  print(displayName); // 输出: Guest

  name = 'Alice';
  displayName = name ?? 'Guest'; // name 不为 null,返回 'Alice'
  print(displayName); // 输出: Alice
}

2. ?. 运算符

  • 作用?. 是条件访问运算符,也称为 null 安全访问运算符。用于在访问对象属性或方法时安全地处理 null 值。如果左侧的对象为 null,整个表达式将返回 null,而不是抛出异常。
  • 使用场景:用于避免因访问 null 对象的属性或方法而引发的运行时错误。

示例:

class User {
  String? name;
  
  User(this.name);
}

void main() {
  User? user;
  print(user?.name); // user 为 null,返回 null

  user = User('Alice');
  print(user?.name); // user 不为 null,返回 'Alice'
}
  • ?? 运算符
    • 用于提供默认值,当左侧表达式为 null 时返回右侧值。
  • ?. 运算符
    • 用于安全地访问对象的属性或方法,如果对象为 null,则整个表达式返回 null,避免运行时错误。

这两个运算符在处理可能的 null 值时非常有用,提高了代码的安全性和可读性。


38. ModalRoute.of() 的目的是什么?

在 Flutter 中,ModalRoute.of(context) 是一个用于获取当前模态路由的静态方法。它的主要目的是在小部件树中查找与给定 BuildContext 相关联的 ModalRoute 实例。这个方法在处理模态对话框、底部抽屉等需要路由管理的场景中非常有用。

主要用途

  • 获取当前路由信息
    • ModalRoute 提供了关于当前路由的信息,例如路由的名称、路由的参数等。通过 ModalRoute.of(context),你可以方便地访问这些信息。
  • 控制路由状态
    • 可以通过获取的 ModalRoute 实例来控制路由的状态,例如使用 Navigator 来返回上一个路由或关闭当前模态对话框。
  • 在小部件中使用路由相关功能
    • 在小部件树中,如果你需要访问当前路由的功能(如获取路由参数或关闭路由),可以通过 ModalRoute.of(context) 来实现。

示例

以下是一个简单的示例,展示如何使用 ModalRoute.of(context)

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: FirstPage(),
    );
  }
}

class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('First Page')),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            Navigator.push(
              context,
              MaterialPageRoute(builder: (context) => SecondPage()),
            );
          },
          child: Text('Go to Second Page'),
        ),
      ),
    );
  }
}

class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // 获取当前的 ModalRoute
    final route = ModalRoute.of(context);

    return Scaffold(
      appBar: AppBar(title: Text('Second Page')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('Current Route: ${route?.settings.name ?? 'Unnamed'}'),
            ElevatedButton(
              onPressed: () {
                Navigator.pop(context); // 返回上一页
              },
              child: Text('Go Back'),
            ),
          ],
        ),
      ),
    );
  }
}

ModalRoute.of(context) 的主要目的是提供对当前模态路由的访问,使得在小部件中能够获取路由信息、控制路由状态以及处理与路由相关的功能。它在构建需要路由管理的应用时非常有用,尤其是在处理对话框和底部抽屉等场景中。


39. Navigator.pushNamed 和 Navigator.pushReplacementNamed 之间的区别是什么?

在 Flutter 中,Navigator.pushNamedNavigator.pushReplacementNamed 都是用于导航到新页面的方法,但它们在路由栈的管理上有显著的区别。以下是这两者的主要区别:

  1. Navigator.pushNamed
  • 功能:将新路由推送到当前导航栈中,当前页面保持在栈中。
  • 行为:新的页面呈现给用户,用户可以通过后退操作返回到之前的页面。
  • 使用场景:适用于需要在多个页面之间来回导航的情况,例如从列表页面导航到详情页面,并允许用户返回。

示例:

Navigator.pushNamed(context, '/detail');
  1. Navigator.pushReplacementNamed
  • 功能:将新路由推送到当前导航栈中,同时将当前路由替换掉。
  • 行为:新的页面呈现给用户,当前页面被移除,用户无法通过后退操作返回到被替换的页面。
  • 使用场景:适用于需要替换当前页面的情况,例如在用户完成某个操作后(如登录后),不希望用户返回到登录页面。

示例:

Navigator.pushReplacementNamed(context, '/home');
  • Navigator.pushNamed
    • 保留当前页面,允许用户返回。
    • 适用于需要在多个页面之间来回导航的场景。
  • Navigator.pushReplacementNamed
    • 替换当前页面,不允许用户返回。
    • 适用于完成操作后需要跳转到新页面的场景,例如登录成功后跳转到主页面。

根据具体的导航需求选择适合的方法,可以提高应用的用户体验和逻辑清晰度。


40. 单实例与作用域实例的区别是什么?

在 Flutter 和 Dart 中,单实例(Singleton)与作用域实例(Scoped Instance)是两种不同的对象管理和创建方式,它们在生命周期、可访问性和使用场景上有显著的区别。以下是它们的主要区别:

1. 单实例(Singleton)

  • 定义:单实例是一种设计模式,确保一个类只有一个实例,并提供一个全局访问点。
  • 生命周期:在应用的整个生命周期内,单实例始终存在,直到应用关闭。
  • 可访问性:无论在应用中的哪个地方,你都可以通过同一个访问点获取该实例。
  • 使用场景:适用于需要全局状态管理或共享资源的情况,例如配置管理、日志记录、数据库连接等。

示例:

class Singleton {
  // 私有构造函数
  Singleton._privateConstructor();

  // 唯一实例
  static final Singleton _instance = Singleton._privateConstructor();

  // 获取实例的方法
  static Singleton get instance => _instance;

  // 示例方法
  void someMethod() {
    print("This is a singleton method.");
  }
}

// 使用
void main() {
  var singleton1 = Singleton.instance;
  var singleton2 = Singleton.instance;

  print(identical(singleton1, singleton2)); // 输出: true
}

2. 作用域实例(Scoped Instance)

  • 定义:作用域实例是根据某个特定的上下文或范围创建的实例,通常在特定的生命周期内有效。
  • 生命周期:作用域实例的生命周期通常与其所在的作用域(如页面、组件或特定的上下文)相关联,当该作用域结束时,实例也会被销毁。
  • 可访问性:作用域实例在其作用域内可访问,通常不跨越不同的作用域。
  • 使用场景:适用于需要在特定上下文中共享状态或资源的情况,例如在某个页面中使用的状态管理、依赖注入等。

示例(使用 Provider 作为作用域实例):

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

// 状态类
class Counter with ChangeNotifier {
  int _count = 0;

  int get count => _count;

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

void main() {
  runApp(
    ChangeNotifierProvider(
      create: (context) => Counter(), // 创建作用域实例
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: CounterPage(),
    );
  }
}

class CounterPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final counter = Provider.of<Counter>(context); // 访问作用域实例

    return Scaffold(
      appBar: AppBar(title: Text('Scoped Instance Example')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('Count: ${counter.count}'),
            ElevatedButton(
              onPressed: counter.increment,
              child: Text('Increment'),
            ),
          ],
        ),
      ),
    );
  }
}
  • 单实例(Singleton)
    • 在整个应用生命周期内保持唯一,适用于全局状态和资源共享。
  • 作用域实例(Scoped Instance)
    • 仅在特定上下文或生命周期内有效,适用于局部状态和资源管理。

根据你的应用需求和架构选择合适的实例管理方式,可以提高代码的可维护性和清晰度。


小结

感谢阅读本文

如果有什么建议,请在评论中让我知道。我很乐意改进。


猫哥 APP

flutter 学习路径


© 猫哥 ducafecat.com

end