使用 GetIt 对 Flutter 应用进行 MVVM 架构设计

从基础开始??‍?

  • Flutter

Flutter 是 Google 的一个开源框架,用于从单一代码库构建美观的、原生编译的、多平台的应用程序。

Flutter 的特性

  1. 快速:Flutter 代码编译为 ARM 或 Intel 机器码以及 JavaScript,可在任何设备上实现快速性能。

  2. 高效:通过热重载快速构建和迭代。更新代码并几乎即时看到更改,而不会丢失状态。

  3. 灵活:通过热重载快速构建和迭代。更新代码并几乎即时看到更改,而不会丢失状态。

  • GetIt

随着您的应用不断发展,总会有一天您需要将应用的逻辑放入与 Widgets 分离的类中。让您的 widgets 不具有直接依赖关系,可以使您的代码更有条理,更易于测试和维护。但现在您需要一种方法来从 UI 代码中访问这些对象。

这就是 GetIt 发挥作用的地方。GetIt 是 Dart 和 Flutter 项目的简单服务定位器。它可以代替Inherited WidgetProvider来从 UI 中访问对象。

由于它不是状态管理解决方案。它是一个对象定位器,所以您还需要其他方法来通知 UI 更改,例如StreamsValueNotifier

我们中的许多人对如何通知 UI 以及如何将其与 MVVM 架构集成感到困惑。本教程将帮助您为大型项目的样板代码设置架构。

  • MVVM – (Model-View-ViewModel)

MVVM 是软件开发中一个非常流行的架构模式,用于将表示层与业务逻辑分离,并将它们与 ViewModels 绑定在一起。

MVVM 的特性

  1. 易于维护:表示层和业务逻辑层是分离的,因此代码易于维护,并且您可以重用代码或 widgets。这对于短期项目可能看起来没有用。但当您创建大型项目时,您会看到它的强大之处,在这些项目中您需要不断地重用代码。

  2. 易于测试:由于所有函数逻辑都写在一个单独的文件中,因此比事件驱动的代码更容易对函数进行单元测试。

我想基础知识就够了,让我们看看一些很酷的东西。 ?

  • 目录结构

structure.png

让我们逐一浏览所有部分——

  • config:包含应用程序的配置,用于响应式应用程序。
  • constant:用于存储应用程序常量,例如任何常见的文本样式、Flutter Toast 等。
  • enum:用于存储应用程序的枚举,目前这里只有一个枚举。
enum ViewState { Idle, Busy }

这个枚举用于识别应用程序何时与服务器或数据库通信,然后它可以根据 ViewState 帮助在 UI 上显示 ProgressIndicator。

  • provider:此目录包含一些关于 GetIt 设置、使用 GetIt 注册 ViewModel 以及用于通知 UI 更改的 ValueNotifier 的重要配置。

GetIt getIt = GetIt.instance;
void setupLocator() {
  getIt.registerLazySingleton(() => NavigationService());
  getIt.registerFactory(() => ApiService());
  getIt.registerFactory(() => HomeScreenViewModel());
}
  • services:如果您正在使用 Firebase 来进行应用程序,那么您可以跳过此目录,否则如果您计划使用自己的服务器,例如 Express、Django、Flask。此目录将非常有用,因为它包含 RESTFUL API 的方法,将响应转换为易于理解的类ApiResponse等。
    您可以查看里面的内容。

  • src:它将包含您所有的源文件。它大致分为 3 个部分

    1. models:用于存储您的业务类。
    2. screens:用于存储您所有的 UI 屏幕。
    3. widgets:用于存储可重用组件。

让我们看看最后两个文件,它们将是我们的应用程序的入口点。

  1. main.dart

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  setupLocator();
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      navigatorKey: getIt<NavigationService>().navigatorKey,
      title: 'Flutter MVVM',
      initialRoute: '/',
      onGenerateRoute: RouteGenerator.generateRoute,
    );
  }
}
  1. route_generator.dart

class RouteGenerator {
  static Route<dynamic> generateRoute(RouteSettings settings) {
    // Getting arguments passed in while calling Navigator.pushNamed
    final args = settings.arguments as dynamic;

    switch (settings.name) {
      case '/':
        return MaterialPageRoute(builder: (_) => const HomeScreen());
      default:
        // If there is no such named route in the switch statement, e.g. /third
        return _errorRoute();
    }
  }

为您一路坚持到这里鼓掌。让我们运行应用程序!?

app.gif

这看起来和新 Flutter 项目的开始一样。那么我们这里做了什么额外的吗?

让我们通过重要文件来理解底层过程。

  • lib/src/screens/home_screen.dart
    这是表示层,即 UI 屏幕,您可以在其中进行设计。
    请注意,我们将 Scaffold 包装在类型为 HomeScreenModel 的BasView Builder中。这会将我们的 UI 与 ViewModel 绑定,并在发生任何更改时通知 UI。

import 'package:flutter/material.dart';
import 'package:flutter_mvvm_with_getit/provider/base_view.dart';
import 'package:flutter_mvvm_with_getit/view/home_screen_viewmodel.dart';

class HomeScreen extends StatefulWidget {
  const HomeScreen({Key? key}) : super(key: key);

  @override
  _HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  @override
  Widget build(BuildContext context) {
    return BaseView<HomeScreenViewModel>(
      builder: (context, model, _) => Scaffold(
        appBar: AppBar(
          title: const Text("Flutter MVVM"),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              const Text(
                'You have pushed the button this many times:',
              ),
              Text(
                model.counter.toString(),
                style: Theme.of(context).textTheme.headline4,
              ),
            ],
          ),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () => model.incrementCounter(),
          child: const Icon(Icons.add),
        ),
      ),
    );
  }
}
  • lib/src/view/home_screen_viewmodel.dart

此文件是我们的 ViewModel 层,由 UI 绑定。在这里我们编写函数逻辑,变量的任何更改都会通知 UI,UI 会相应地重建。

请注意,我们有一个 counter 变量,它在 home_screen 中使用,并且一个增加 counter 的方法也在 home_screen 中使用。

import 'package:flutter_mvvm_with_getit/provider/base_model.dart';

class HomeScreenViewModel extends BaseModel {
  int counter = 0;

  void incrementCounter() {
    counter++;
    notifyListeners();
  }
}

在最后一行,有一个函数——notifyListeners,这个函数通知 UI 某个变量已更改,并根据更改重建您的 UI。

好了,各位,这就是使用 GetIt 通过 MVVM 架构构建 Flutter 应用程序。

我希望您能从本教程中学到新东西,并将用这个样板代码创建一些很棒的东西。

我还附上了 Github 仓库,您可以 Fork 并将其用作应用程序的样板代码。
该仓库将包含您在创建任何大型应用程序时将使用的所有重要文件夹和文件。

仍有疑问?在评论区告诉我??

Github 仓库: Flutter MMVM with GetIt

与我联系: LinkedIn

GitHub

查看 Github