在这里插入图片描述

应用架构是Flutter项目的骨架,它决定了代码的组织方式、模块间的依赖关系、数据流向和技术选型。一个好的架构设计能够提高代码的可维护性、可扩展性和团队协作效率。

在这个小区门禁管理项目中,我们采用了分层架构和模块化设计,确保每个功能模块职责清晰、低耦合高内聚。

这篇讲应用架构的实现,重点是如何构建一个可扩展、可维护的Flutter应用架构。

应用架构的设计思路是:分层清晰 + 模块化 + 依赖注入

// 主入口文件 - main.dart
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'app/routes/app_pages.dart';
import 'app/core/theme/app_theme.dart';
import 'app/core/services/storage_service.dart';
import 'app/core/services/api_service.dart';

void main() async {
  // 确保Flutter绑定初始化
  WidgetsFlutterBinding.ensureInitialized();
  
  // 初始化服务
  await _initServices();
  
  // 初始化屏幕适配
  await ScreenUtil.ensureScreenSize();
  
  runApp(const MyApp());
}

Future<void> _initServices() async {
  // 初始化存储服务
  await Get.putAsync(() async => StorageService());
  
  // 初始化API服务
  await Get.putAsync(() async => ApiService());
}

应用入口设计

  • 使用 WidgetsFlutterBinding.ensureInitialized() 确保Flutter绑定初始化。
  • 异步初始化核心服务:存储服务和API服务。
  • 使用 Get.putAsync() 进行依赖注入。
  • 初始化屏幕适配库 flutter_screenutil
class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return ScreenUtilInit(
      designSize: const Size(375, 812), // iPhone X尺寸作为设计基准
      minTextAdapt: true,
      splitScreenMode: true,
      builder: (context, child) {
        return GetMaterialApp(
          title: '小区门禁管理',
          debugShowCheckedModeBanner: false,
          theme: AppTheme.lightTheme,
          darkTheme: AppTheme.darkTheme,
          themeMode: ThemeMode.system,
          defaultTransition: Transition.cupertino,
          transitionDuration: const Duration(milliseconds: 300),
          initialRoute: AppPages.initial,
          getPages: AppPages.routes,
          builder: (context, widget) {
            return MediaQuery(
              data: MediaQuery.of(context).copyWith(
                textScaleFactor: 1.0, // 禁用系统字体缩放
              ),
              child: widget!,
            );
          },
        );
      },
    );
  }
}

应用根组件设计

  • 使用 ScreenUtilInit 进行屏幕适配初始化。
  • 使用 GetMaterialApp 作为应用根组件。
  • 配置主题、路由、转场动画等全局设置。
  • 禁用系统字体缩放,确保UI一致性。
// 路由配置 - app/routes/app_pages.dart
import 'package:get/get.dart';
import '../pages/home/home_binding.dart';
import '../pages/home/home_view.dart';
import '../pages/access/access_binding.dart';
import '../pages/access/access_view.dart';
import '../pages/profile/profile_binding.dart';
import '../pages/profile/profile_view.dart';
import '../pages/property/property_binding.dart';
import '../pages/property/property_view.dart';

class AppPages {
  static const initial = '/';
  static final routes = [
    GetPage(
      name: '/',
      page: () => const HomeView(),
      binding: HomeBinding(),
      transition: Transition.fadeIn,
    ),
    GetPage(
      name: '/access',
      page: () => const AccessView(),
      binding: AccessBinding(),
      transition: Transition.rightToLeft,
    ),
    GetPage(
      name: '/profile',
      page: () => const ProfileView(),
      binding: ProfileBinding(),
      transition: Transition.rightToLeft,
    ),
    GetPage(
      name: '/property',
      page: () => const PropertyView(),
      binding: PropertyBinding(),
      transition: Transition.rightToLeft,
    ),
  ];
}

路由配置设计

  • 使用 GetX 的路由系统进行页面管理。
  • 每个页面都配置了对应的 Binding 进行依赖注入。
  • 配置页面转场动画,提升用户体验。
  • 路由名称语义化,便于维护。
// 主题配置 - app/core/theme/app_theme.dart
import 'package:flutter/material.dart';

class AppTheme {
  static ThemeData get lightTheme {
    return ThemeData(
      useMaterial3: true,
      brightness: Brightness.light,
      colorScheme: ColorScheme.fromSeed(
        seedColor: const Color(0xFF2196F3),
        brightness: Brightness.light,
      ),
      appBarTheme: const AppBarTheme(
        centerTitle: true,
        elevation: 0,
        backgroundColor: Colors.transparent,
        foregroundColor: Colors.black87,
        titleTextStyle: TextStyle(
          fontSize: 18,
          fontWeight: FontWeight.w600,
        ),
      ),
      elevatedButtonTheme: ElevatedButtonThemeData(
        style: ElevatedButton.styleFrom(
          backgroundColor: const Color(0xFF2196F3),
          foregroundColor: Colors.white,
          elevation: 2,
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(8),
          ),
          padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
        ),
      ),
      cardTheme: CardTheme(
        elevation: 2,
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(12),
        ),
      ),
    );
      ),
    );
  }
}

主题配置设计

  • 提供亮色和暗色两种主题。
  • 使用 Material 3 设计规范。
  • 统一配置 AppBar、Button、Card 等组件样式。
  • 主题色使用蓝色系,保持视觉一致性。
// 存储服务 - app/core/services/storage_service.dart
import 'package:get/get.dart';
import 'package:shared_preferences/shared_preferences.dart';

class StorageService extends GetxService {
  late SharedPreferences _prefs;

  Future<void> init() async {
    _prefs = await SharedPreferences.getInstance();
  }

  // 用户信息存储
  Future<void> saveUserInfo(Map<String, dynamic> userInfo) async {
    await _prefs.setString('user_info', userInfo.toString());
  }

  Map<String, dynamic>? getUserInfo() {
    final userInfoStr = _prefs.getString('user_info');
    if (userInfoStr != null) {
      // 这里需要实际的JSON解析
      return {'name': '用户', 'phone': '13800138000'};
    }
    return null;
  }

  // 主题设置
  Future<void> setThemeMode(String themeMode) async {
    await _prefs.setString('theme_mode', themeMode);
  }

  String getThemeMode() {
    return _prefs.getString('theme_mode') ?? 'system';
  }

  // 语言设置
  Future<void> setLanguage(String language) async {
    await _prefs.setString('language', language);
  }

  String getLanguage() {
    return _prefs.getString('language') ?? 'zh_CN';
  }

  // 清除所有数据
  Future<void> clearAll() async {
    await _prefs.clear();
  }
}

存储服务设计

  • 使用 SharedPreferences 进行本地数据存储。
  • 提供用户信息、主题、语言等常用设置的存储。
  • 使用 GetX 的 Service 生命周期管理。
  • 提供清除数据的方法,便于用户登出。
// API服务 - app/core/services/api_service.dart
import 'package:get/get.dart';
import 'package:dio/dio.dart';

class ApiService extends GetxService {
  late Dio _dio;
  
  static const String baseUrl = 'https://api.example.com';
  
  
  void onInit() {
    super.onInit();
    _dio = Dio(BaseOptions(
      baseUrl: baseUrl,
      connectTimeout: const Duration(seconds: 10),
      receiveTimeout: const Duration(seconds: 10),
      headers: {
        'Content-Type': 'application/json',
        'Accept': 'application/json',
      },
    ));
    
    // 添加拦截器
    _dio.interceptors.add(LogInterceptor(
      requestBody: true,
      responseBody: true,
      logPrint: true,
    ));
    
    _dio.interceptors.add(InterceptorsWrapper(
      onRequest: (options, handler) {
        // 添加认证token
        final token = getAuthToken();
        if (token != null) {
          options.headers['Authorization'] = 'Bearer $token';
        }
        return handler.next(options);
      },
      onError: (error, handler) {
        // 错误处理
        _handleError(error);
        return handler.next(error);
      },
    ));
  }
}

API服务设计

  • 使用 Dio 作为HTTP客户端。
  • 配置基础URL、超时时间、请求头等。
  • 添加日志拦截器便于调试。
  • 添加认证拦截器自动处理token。
  • 统一的错误处理和用户提示。
// 数据模型 - app/models/user_model.dart
class UserModel {
  final String id;
  final String name;
  final String phone;
  final String email;
  final String avatar;
  final String building;
  final String unit;
  final String room;
  final DateTime joinDate;
  final String status;

  const UserModel({
    required this.id,
    required this.name,
    required this.phone,
    required this.email,
    required this.avatar,
    required this.building,
    required this.unit,
    required this.room,
    required this.joinDate,
    required this.status,
  });

  factory UserModel.fromJson(Map<String, dynamic> json) {
    return UserModel(
      id: json['id'] ?? '',
      name: json['name'] ?? '',
      phone: json['phone'] ?? '',
      email: json['email'] ?? '',
      avatar: json['avatar'] ?? '',
      building: json['building'] ?? '',
      unit: json['unit'] ?? '',
      room: json['room'] ?? '',
      joinDate: DateTime.parse(json['joinDate'] ?? ''),
      status: json['status'] ?? '',
    );
  }

  Map<String, dynamic> toJson() {
    return {
      'id': id,
      'name': name,
      'phone': phone,
      'email': email,
      'avatar': avatar,
      'building': building,
      'unit': unit,
      'room': room,
      'joinDate': joinDate.toIso8601String(),
      'status': status,
    };
  }
}

数据模型设计

  • 使用不可变对象,确保数据安全性。
  • 提供 fromJsontoJson 方法进行序列化。
  • 提供 copyWith 方法进行对象复制。
  • 所有字段都有默认值,避免空指针异常。
// 控制器基类 - app/core/base/base_controller.dart
import 'package:get/get.dart';

abstract class BaseController extends GetxController {
  // 加载状态
  final RxBool isLoading = false.obs;
  
  // 错误信息
  final RxString errorMessage = ''.obs;
  
  // 设置加载状态
  void setLoading(bool loading) {
    isLoading.value = loading;
  }
}

控制器基类设计

  • 提供通用的加载状态管理。
  • 统一的错误处理和用户提示。
  • 使用响应式变量,便于UI状态绑定。
  • onClose 时正确释放资源。
// 首页控制器 - app/pages/home/home_controller.dart
import 'package:get/get.dart';
import '../../../core/base/base_controller.dart';
import '../../../models/user_model.dart';
import '../../../core/services/storage_service.dart';

class HomeController extends BaseController {
  final Rx<UserModel?> currentUser = Rx<UserModel?>(null);
  final RxList<Map<String, dynamic>> quickActions = <Map<String, dynamic>>[].obs;
  
  
  void onInit() {
    super.onInit();
    _loadUserData();
    _initQuickActions();
  }
  
  void _loadUserData() {
    final storageService = Get.find<StorageService>();
    final userInfo = storageService.getUserInfo();
    
    if (userInfo != null) {
      currentUser.value = UserModel(
        id: userInfo['id'] ?? '',
        name: userInfo['name'] ?? '用户',
        phone: userInfo['phone'] ?? '',
        email: userInfo['email'] ?? '',
        avatar: userInfo['avatar'] ?? '',
        building: userInfo['building'] ?? '',
        unit: userInfo['unit'] ?? '',
        room: userInfo['room'] ?? '',
        joinDate: DateTime.now(),
        status: userInfo['status'] ?? 'active',
      );
    }
  }
  
  void _initQuickActions() {
    quickActions.value = [
      {
        'icon': Icons.announcement,
        'title': '公告',
        'route': '/announcements',
      },
      {
        'icon': Icons.build,
        'title': '报修',
        'route': '/repairs',
      },
      {
        'icon': Icons.payment,
        'title': '缴费',
        'route': '/payments',
      },
      {
        'icon': Icons.person_add,
        'title': '访客',
        'route': '/visitors',
      },
    ];
  }

}

控制器实现

  • 继承 BaseController 获得通用功能。
  • 使用响应式变量管理UI状态。
  • 从存储服务加载用户数据。
  • 提供页面导航和登出功能。

架构设计原则

1. 分层架构

  • 表现层:UI组件和页面
  • 业务层:控制器和业务逻辑
  • 数据层:模型和数据服务
  • 基础设施层:网络、存储、工具类

2. 依赖注入

  • 使用 GetX 的依赖注入系统
  • 服务单例模式管理
  • 控制器生命周期管理

3. 模块化设计

  • 按功能模块组织代码
  • 模块间低耦合高内聚
  • 清晰的依赖关系

4. 响应式编程

  • 使用响应式变量管理状态
  • UI自动响应数据变化
  • 简化状态管理逻辑

技术选型说明

1. 状态管理

  • GetX:轻量级状态管理和依赖注入
  • 响应式变量:自动UI更新
  • 路由管理:声明式路由配置

2. 网络请求

  • Dio:功能强大的HTTP客户端
  • 拦截器:统一处理认证和日志
  • 错误处理:统一的错误处理机制

3. 本地存储

  • SharedPreferences:轻量级键值存储
  • 存储服务:封装存储操作
  • 数据持久化:用户设置和缓存

4. 屏幕适配

  • flutter_screenutil:屏幕尺寸适配
  • 响应式布局:适配不同屏幕尺寸
  • 设计基准:iPhone X作为设计基准

扩展性考虑

1. 功能扩展

  • 插件化架构支持功能模块扩展
  • 标准化的页面和控制器模板
  • 统一的数据模型和服务接口

2. 平台扩展

  • 跨平台兼容性设计
  • 平台特定功能的条件编译
  • 统一的API接口抽象

3. 团队协作

  • 清晰的代码组织结构
  • 统一的编码规范和注释
  • 完善的文档和示例

这个架构设计为小区门禁管理应用提供了坚实的技术基础,确保代码的可维护性、可扩展性和团队协作效率。


欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐