0


使用 Flutter 实现 MVVM 架构

文章目录

在本文中,我们将探讨如何在 Flutter 应用中实现 MVVM(Model-View-ViewModel)架构。MVVM 架构有助于保持代码整洁、可维护,同时提高开发效率。我们将通过高维度的架构设计和具体的代码案例来介绍如何在 Flutter 中实现 MVVM。

一、什么是 MVVM 架构?

MVVM(Model-View-ViewModel)是一种软件架构设计模式,用于将业务逻辑、界面表示和用户交互分离。MVVM 架构包含以下三个主要组件:

  • Model:负责处理数据和业务逻辑。
  • View:负责显示 UI,并将用户操作传递给 ViewModel。
  • ViewModel:负责处理 View 的输入,并更新 Model,同时通知 View 更新。

通过将这三个组件分离,我们可以更容易地维护和扩展代码,同时保持代码整洁。

二、MVVM 架构设计

要在 Flutter 中实现 MVVM 架构,我们需要创建 Model、View 和 ViewModel 类,并使用 Flutter 的数据绑定机制将它们连接起来。这里是一个高维度的架构设计:

  1. Model:创建一个包含业务逻辑的 Model 类。这个类可以包含数据模型、网络请求、数据库操作等。
  2. ViewModel:创建一个继承 ChangeNotifier 的 ViewModel 类。这个类将处理 View 的输入,并更新 Model。同时,通过调用 notifyListeners() 通知 View 更新。
  3. View:创建一个 StatefulWidget,并在其 build 方法中构建 UI。将 ViewModel 作为 ChangeNotifierProvider 的参数,以便在子组件中访问 ViewModel。
  4. 数据绑定:使用 Consumer 或 context.watch() 监听 ViewModel 的变化,并在 View 中更新 UI。

三、代码案例

接下来,我们将通过一个简单的计数器应用来演示如何在 Flutter 中实现 MVVM 架构。

3.1 Model

首先,我们创建一个简单的

Counter

类作为 Model,用于存储计数器的值并进行增加操作。

classCounter{
  int _value =0;

  int get value => _value;voidincrement(){
    _value++;}}

3.2 ViewModel

接下来,我们创建一个继承

ChangeNotifier

的

CounterViewModel

类。这个类将处理 View 的输入,并更新 Model。同时,通过调用

notifyListeners()

通知 View 更新。

import'package:flutter/foundation.dart';import'counter.dart';classCounterViewModelextendsChangeNotifier{finalCounter _counter =Counter();

  int get value => _counter.value;voidincrement(){
    _counter.increment();notifyListeners();}}

3.3 View

然后,我们创建一个 StatefulWidget,并在其

build

方法中构建 UI。将 ViewModel 作为

ChangeNotifierProvider

的参数,以便在子组件中访问 ViewModel。

import'package:flutter/material.dart';import'package:provider/provider.dart';import'counter_view_model.dart';voidmain(){runApp(MyApp());}classMyAppextendsStatelessWidget{@overrideWidgetbuild(BuildContext context){returnMaterialApp(
      home:ChangeNotifierProvider(
        create:(context)=>CounterViewModel(),
        child:CounterPage(),),);}}classCounterPageextendsStatefulWidget{@override
  _CounterPageState createState()=>_CounterPageState();}class _CounterPageState extendsState<CounterPage>{@overrideWidgetbuild(BuildContext context){returnScaffold(
      appBar:AppBar(title:Text('MVVM Counter')),
      body:Center(
        child:Consumer<CounterViewModel>(
          builder:(context, viewModel, child){returnText('Counter: ${viewModel.value}');},),),
      floatingActionButton:FloatingActionButton(
        onPressed:(){
          context.read<CounterViewModel>().increment();},
        child:Icon(Icons.add),),);}}

在这个示例中,我们使用

ChangeNotifierProvider

将 ViewModel 提供给子组件,并使用

Consumer

监听 ViewModel 的变化。当 ViewModel 更新时,

Consumer

会自动重建 UI,以显示最新的计数器值。另外,我们使用

context.read<CounterViewModel>().increment()

来调用 ViewModel 中的

increment

方法,以更新计数器。

四、扩展 MVVM 架构

虽然我们已经演示了一个简单的 MVVM 架构实现,但在实际项目中,你可能会遇到更复杂的场景。接下来,我们将探讨一些扩展 MVVM 架构的方法,以满足不同的需求。

4.1 引入服务层

在大型项目中,我们可能需要处理更复杂的业务逻辑,如网络请求、数据库操作等。为了保持 Model 的简洁,我们可以引入服务层,将这些逻辑封装为独立的服务类。然后,在 ViewModel 中调用这些服务类来更新 Model。

例如,我们可以创建一个

CounterService

类,负责从远程服务器获取和更新计数器值。然后,在

CounterViewModel

中调用这个服务类,而不是直接操作 Model。

4.2 使用依赖注入

依赖注入是一种编程技术,用于将对象的依赖项(如服务类)动态地传递给它们。通过使用依赖注入,我们可以更灵活地管理和测试应用的各个组件。

在 Flutter 中,我们可以使用

provider

包提供的

ProxyProvider

或其他第三方库(如

get_it

、

injectable

等)来实现依赖注入。这样,我们可以将服务类和其他依赖项注入到 ViewModel 中,而不是在 ViewModel 内部创建它们。

4.3 状态管理

虽然 MVVM 架构提供了一种有效的状态管理方法,但在复杂的应用中,我们可能需要更强大的状态管理解决方案。在 Flutter 中,有许多状态管理库可供选择,如

provider

、

bloc

、

mobx

等。这些库可以与 MVVM 架构结合使用,以实现更高效的状态管理。

例如,我们可以使用

bloc

库来实现 ViewModel,将业务逻辑和状态管理进一步解耦。这样,我们可以在不修改 View 的情况下,更容易地重构和测试 ViewModel。

4.4 遵循最佳实践

在实现 MVVM 架构时,我们应遵循一些最佳实践,以确保代码的可维护性和可扩展性。例如:

  • 保持 Model、View 和 ViewModel 的职责单一,避免将过多的逻辑放入一个类中。
  • 使用接口和抽象类来定义 Model 和 ViewModel,以便在不同的实现和平台之间共享代码。
  • 编写单元测试和集成测试,确保应用的正确性和稳定性。
  • 优化性能,避免不必要的重绘和重建。

通过遵循这些最佳实践,我们可以确保 MVVM 架构在实际项目中发挥最大的作用。

五、实战案例:待办事项应用

为了更好地理解如何在实际项目中应用 MVVM 架构,我们将通过一个待办事项应用的实战案例来演示。这个应用将包含以下功能:

  • 显示待办事项列表
  • 添加新的待办事项
  • 标记待办事项为完成或未完成
  • 删除待办事项

5.1 Model

首先,我们创建一个简单的

TodoItem

类作为 Model,用于存储待办事项的信息。

classTodoItem{String title;
  bool isDone;TodoItem({required this.title,this.isDone =false});}

5.2 服务层

接着,我们创建一个

TodoService

类,负责处理待办事项的业务逻辑,如添加、删除、更新等。

classTodoService{List<TodoItem> _todos =[];List<TodoItem>get todos => _todos;voidaddTodo(TodoItem todo){
    _todos.add(todo);}voidremoveTodo(TodoItem todo){
    _todos.remove(todo);}voidtoggleTodoStatus(TodoItem todo){
    todo.isDone =!todo.isDone;}}

5.3 ViewModel

然后,我们创建一个继承

ChangeNotifier

的

TodoViewModel

类。这个类将处理 View 的输入,并调用

TodoService

来更新 Model。同时,通过调用

notifyListeners()

通知 View 更新。

import'package:flutter/foundation.dart';import'todo_item.dart';import'todo_service.dart';classTodoViewModelextendsChangeNotifier{finalTodoService _todoService =TodoService();List<TodoItem>get todos => _todoService.todos;voidaddTodo(String title){
    _todoService.addTodo(TodoItem(title: title));notifyListeners();}voidremoveTodo(TodoItem todo){
    _todoService.removeTodo(todo);notifyListeners();}voidtoggleTodoStatus(TodoItem todo){
    _todoService.toggleTodoStatus(todo);notifyListeners();}}

5.4 View

最后,我们创建 View 层,包括一个

TodoListPage

和一个

TodoItemWidget

。

TodoListPage

负责显示待办事项列表和处理用户输入,而

TodoItemWidget

负责渲染单个待办事项。

import'package:flutter/material.dart';import'package:provider/provider.dart';import'todo_view_model.dart';import'todo_item.dart';voidmain(){runApp(MyApp());}classMyAppextendsStatelessWidget{@overrideWidgetbuild(BuildContext context){returnMaterialApp(
      home:ChangeNotifierProvider(
        create:(context)=>TodoViewModel(),
        child:TodoListPage(),),);}}classTodoListPageextendsStatelessWidget{@overrideWidgetbuild(BuildContext context){returnScaffold(
      appBar:AppBar(title:Text('Todo List')),
      body:Consumer<TodoViewModel>(
        builder:(context, viewModel, child){returnListView.builder(
            itemCount: viewModel.todos.length,
            itemBuilder:(context, index){returnTodoItemWidget(
                todo: viewModel.todos[index],
                onToggle:(){
                  viewModel.toggleTodoStatus(viewModel.todos[index]);},
                onDelete:(){
                  viewModel.removeTodo(viewModel.todos[index]);},);},);},),
      floatingActionButton:FloatingActionButton(
        onPressed:()async{String? newTitle =await showDialog<String>(
            context: context,
            builder:(context){returnAddTodoDialog();},);if(newTitle !=null&& newTitle.isNotEmpty){
            context.read<TodoViewModel>().addTodo(newTitle);}},
        child:Icon(Icons.add),),);}}classTodoItemWidgetextendsStatelessWidget{finalTodoItem todo;finalVoidCallback onToggle;finalVoidCallback onDelete;TodoItemWidget({required this.todo, required this.onToggle, required this.onDelete});@overrideWidgetbuild(BuildContext context){returnListTile(
      title:Text(todo.title),
      leading:Checkbox(
        value: todo.isDone,
        onChanged:(bool? value){onToggle();},),
      trailing:IconButton(
        icon:Icon(Icons.delete),
        onPressed: onDelete,),);}}classAddTodoDialogextendsStatelessWidget{finalTextEditingController _controller =TextEditingController();@overrideWidgetbuild(BuildContext context){returnAlertDialog(
      title:Text('Add Todo'),
      content:TextField(
        controller: _controller,
        decoration:InputDecoration(hintText:'Todo title'),),
      actions:[TextButton(
          child:Text('Cancel'),
          onPressed:(){Navigator.of(context).pop();},),TextButton(
          child:Text('Add'),
          onPressed:(){Navigator.of(context).pop(_controller.text);},),],);}}

在这个示例中,我们创建了一个待办事项应用,使用 MVVM 架构将业务逻辑、界面表示和用户交互分离。通过这种方式,我们可以更容易地维护和扩展代码,同时保持代码整洁。

六、使用 Riverpod 库实现一个基于 MVVM 架构的计数器应用

在这个示例中,我们将使用 Riverpod 库实现一个基于 MVVM 架构的计数器应用。我们将遵循上文中描述的 MVVM 架构设计,并使用 Riverpod 替换 Provider 作为状态管理库。

首先,请确保已在

pubspec.yaml

文件中添加了

riverpod

和

flutter_riverpod

依赖:

dependencies:flutter:sdk: flutter
  flutter_riverpod: ^1.0.0

接下来,我们将创建 Model、ViewModel 和 View 类,并使用 Riverpod 将它们连接起来。

6.1 Model

创建一个简单的

Counter

类作为 Model,用于存储计数器的值并进行增加操作。

classCounter{
  int _value =0;

  int get value => _value;voidincrement(){
    _value++;}}

6.2 ViewModel

创建一个继承

StateNotifier

的

CounterViewModel

类。这个类将处理 View 的输入,并更新 Model。同时,通过调用

state

属性通知 View 更新。

import'package:flutter_riverpod/flutter_riverpod.dart';import'counter.dart';classCounterViewModelextendsStateNotifier<Counter>{CounterViewModel():super(Counter());

  int get value => state.value;voidincrement(){
    state =Counter().._value = state.value +1;}}

6.3 View

创建一个 StatelessWidget,并在其

build

方法中构建 UI。将 ViewModel 作为

StateNotifierProvider

的参数,以便在子组件中访问 ViewModel。

import'package:flutter/material.dart';import'package:flutter_riverpod/flutter_riverpod.dart';import'counter_view_model.dart';voidmain(){runApp(ProviderScope(child:MyApp()));}classMyAppextendsStatelessWidget{@overrideWidgetbuild(BuildContext context){returnMaterialApp(
      home:CounterPage(),);}}classCounterPageextendsStatelessWidget{@overrideWidgetbuild(BuildContext context){returnScaffold(
      appBar:AppBar(title:Text('Riverpod MVVM Counter')),
      body:Center(
        child:Consumer(
          builder:(context, watch, child){final viewModel =watch(counterViewModelProvider);returnText('Counter: ${viewModel.value}');},),),
      floatingActionButton:FloatingActionButton(
        onPressed:(){
          context.read(counterViewModelProvider.notifier).increment();},
        child:Icon(Icons.add),),);}}

在这个示例中,我们使用

StateNotifierProvider

将 ViewModel 提供给子组件,并使用

Consumer

监听 ViewModel 的变化。当 ViewModel 更新时,

Consumer

会自动重建 UI,以显示最新的计数器值。另外,我们使用

context.read(counterViewModelProvider.notifier).increment()

来调用 ViewModel 中的

increment

方法,以更新计数器。

最后,别忘了在 ViewModel 文件中定义 Riverpod provider:

import'package:flutter_riverpod/flutter_riverpod.dart';final counterViewModelProvider =StateNotifierProvider<CounterViewModel,Counter>((ref){returnCounterViewModel();});

6.4 Riverpod 和 Provider 的区别

Riverpod 是一个用于状态管理的 Flutter 库,它提供了一种声明式、灵活且安全的方式来管理和访问应用程序的状态。在我们的示例中,我们使用 Riverpod 替换了前文案例中的 Provider 库,以实现 MVVM 架构。

以下是 Riverpod 在示例中的作用以及与前文案例的区别:

  1. 声明式 Provider:在 Riverpod 中,我们使用声明式的方式来定义 Provider。这意味着我们可以在全局范围内定义 Provider,而不需要将其放入 Widget 树中。这使得代码更易于阅读和维护。与前文案例相比,我们不再使用 ChangeNotifierProvider,而是使用 StateNotifierProvider 来创建 ViewModel 的实例。
final counterViewModelProvider =StateNotifierProvider<CounterViewModel,Counter>((ref){returnCounterViewModel();});
  1. StateNotifier:在 Riverpod 示例中,我们使用 StateNotifier 替换了 ChangeNotifier。StateNotifier 是 Riverpod 库的一部分,它提供了一种简单的状态管理机制。与 ChangeNotifier 相比,StateNotifier 具有更简洁的 API,并且避免了一些潜在的性能问题。在 ViewModel 中,我们继承 StateNotifier 并使用 state 属性来通知 View 更新。
classCounterViewModelextendsStateNotifier<Counter>{// ...}
  1. Consumer 和 watch:在 Riverpod 示例中,我们使用 Consumer 和 watch 函数来监听 ViewModel 的变化。Consumer 和 watch 函数是 Riverpod 库提供的数据绑定机制,它们可以自动重建 UI 以显示最新的状态。与前文案例中的 context.watch() 相比,Riverpod 的 watch 函数提供了更简洁的语法。
child:Consumer(
  builder:(context, watch, child){final viewModel =watch(counterViewModelProvider);returnText('Counter: ${viewModel.value}');},),
  1. 访问 ViewModel:在 Riverpod 示例中,我们使用 context.read() 函数来访问 ViewModel 并调用其方法。与前文案例中的 context.read() 相比,Riverpod 的 context.read() 函数提供了更简洁的语法。此外,我们需要使用 notifier 属性来访问 StateNotifier 的实例。
onPressed:(){
  context.read(counterViewModelProvider.notifier).increment();},

总之,Riverpod 在示例中的作用主要是提供状态管理和数据绑定。与前文案例相比,Riverpod 提供了更简洁的 API、更灵活的状态管理机制以及更安全的访问方式。这些特性使得 Riverpod 成为实现 MVVM 架构的一个很好的选择。

七、结论

MVVM 架构是一种强大的设计模式,可以帮助我们构建可维护、可测试、可扩展的应用。在 Flutter 中,我们可以利用其强大的数据绑定和状态管理特性,轻松实现 MVVM 架构。

在本文中,我们介绍了 MVVM 架构的基本概念,展示了如何在 Flutter 中实现 MVVM 架构,并通过一个待办事项应用的实战案例,演示了如何在实际项目中应用 MVVM 架构。

希望这篇文章能帮助你理解和掌握 MVVM 架构,为你的 Flutter 项目提供有用的参考。

标签: flutter 架构

本文转载自: https://blog.csdn.net/mba16c35/article/details/138773763
版权归原作者 陆业聪 所有, 如有侵权,请联系我们删除。

“使用 Flutter 实现 MVVM 架构”的评论:

还没有评论