当前位置: 首页 > news >正文

【flutter for open harmony】第三方库 Flutter 鸿蒙实战:get_it 依赖注入 + 模块化架构优化,项目秒变企业级✨

🚀 Flutter 鸿蒙实战:get_it 依赖注入 + 模块化架构优化,项目秒变企业级✨

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


👋 前言

哈喽各位小伙伴!我是持续深耕 Flutter 鸿蒙跨平台开发的大学生开发者~
前面我们已经搞定了路由、图片缓存、搜索、状态管理等核心功能,但是随着项目越来越大,你有没有发现一个致命问题:
代码越来越乱、类与类之间紧耦合、修改一处牵一发而动全身、测试起来超级麻烦?

今天这篇就带大家彻底解决这个痛点,实现get_it 依赖注入 + 模块化架构优化,让你的项目结构清晰、松耦合、易维护、可测试,直接从“学生级项目”升级为“企业级架构”!🚀
全程代码可直接复制、鸿蒙真机完美运行,不管是写 CSDN 博客、课程设计、大创项目还是鸿蒙竞赛,这波优化都是超级加分项!😎


🎯 本篇你能学到什么?

  • ✅ Flutter 鸿蒙环境接入 get_it 依赖注入容器
  • ✅ 掌握“服务定位器”模式,彻底解耦类与类之间的依赖
  • ✅ 搭建标准化模块化架构,分层清晰(DI层、服务层、状态层、页面层)
  • ✅ 重构现有代码,将所有服务、Provider 改为依赖注入模式
  • ✅ 学会单例(Singleton)、工厂(Factory)两种注册方式的区别与使用
  • ✅ 理解模块化架构的核心思想,以后写大型项目不迷路
  • ✅ 鸿蒙项目架构优化实战,提升代码可维护性和可扩展性

🧰 本次用到的核心依赖

  • get_it: ^7.2.0
    Flutter 最流行的依赖注入库,轻量、高效、无侵入,完美适配鸿蒙系统
  • Flutter 版本:3.32.4-ohos-0.0.1
  • OpenHarmony SDK:API 10
  • 其他依赖:provider、shared_preferences(复用之前的)

🤔 为什么要做依赖注入 + 模块化架构?

在没有优化前,你的项目大概率是这样的:
❌ 类之间直接依赖,比如 UserProvider 直接调用 StorageService 的静态方法,紧耦合难以修改
❌ 每个页面都要手动创建 Provider、Service 实例,代码冗余
❌ 测试困难,无法轻松模拟依赖(比如模拟本地存储数据)
❌ 项目结构混乱,文件杂乱无章,找代码要翻半天
❌ 新增功能时,需要修改多处代码,容易出错
❌ 鸿蒙项目后期扩展困难,多人协作容易冲突

优化后,直接实现“脱胎换骨”:
✅ 类之间松耦合,依赖通过注入传递,修改一处不影响其他地方
✅ 全局统一管理所有依赖,哪里需要哪里调用,无需重复创建
✅ 支持单例/工厂模式,合理管理实例生命周期
✅ 模块化分层,结构清晰,找代码一目了然
✅ 易于单元测试,可轻松 mock 依赖
✅ 鸿蒙项目可扩展性拉满,多人协作更高效
✅ 代码更规范、更专业,符合企业级开发标准


🚀 完整实现步骤(超详细,逐行可抄)

1️⃣ 添加 get_it 依赖到 pubspec.yaml

dependencies:flutter:sdk:flutter# 核心:依赖注入容器get_it:^7.2.0# 复用之前的依赖provider:^6.1.2shared_preferences:^2.2.2cached_network_image:^3.3.1shimmer:^3.0.0

执行安装命令,确保依赖生效:

flutter pub get

✨ 小提示:get_it 是纯 Dart 库,无需任何原生改造,鸿蒙设备直接运行,无任何兼容问题!


2️⃣ 搭建模块化架构目录(核心第一步)

先重构项目目录,实现分层模块化,告别杂乱无章!
最终目录结构(复制直接用):

lib/ ├── di/ # 依赖注入层(核心) │ └── injection.dart # 所有依赖的注册与管理 ├── services/ # 服务层(封装通用功能) │ ├── storage_service.dart # 本地存储服务 │ └── search_history_service.dart # 搜索历史服务 ├── providers/ # 状态管理层(管理页面状态) │ ├── user_provider.dart # 用户状态 │ ├── cart_provider.dart # 购物车状态 │ ├── product_provider.dart # 商品状态 │ └── search_provider.dart # 搜索状态 ├── pages/ # 页面层(所有页面) │ ├── home_page.dart │ ├── login_page.dart │ ├── cart_page.dart │ └── ...(其他页面) ├── widgets/ # 组件层(通用组件) │ ├── cached_image.dart # 图片缓存组件 │ └── ...(其他组件) ├── router/ # 路由层 │ └── app_router.dart └── main.dart # 入口文件

各层职责说明(划重点):

  • DI层:统一注册所有依赖,全局提供实例,解耦核心
  • 服务层:封装通用功能(本地存储、网络请求、搜索历史),可复用
  • 状态管理层:管理页面状态,依赖服务层,不直接操作底层功能
  • 页面层:只负责UI展示和用户交互,依赖状态层,不直接依赖服务
  • 组件层:通用UI组件,全项目复用,无业务逻辑

3️⃣ 实现依赖注入核心(injection.dart)

新建lib/di/injection.dart,这是整个依赖注入的“大脑”,所有服务、Provider 都在这里注册!

import'package:get_it/get_it.dart';import'../services/storage_service.dart';import'../services/search_history_service.dart';import'../providers/user_provider.dart';import'../providers/cart_provider.dart';import'../providers/product_provider.dart';import'../providers/search_provider.dart';// 初始化 get_it 实例(全局唯一)finalgetIt=GetIt.instance;// 注册所有依赖的方法Future<void>initInjection()async{// --------------------------// 1. 服务层(Service)注册// --------------------------// 本地存储服务:单例(全生命周期唯一)getIt.registerSingletonAsync<StorageService>(()async{finalservice=StorageService();awaitservice.init();// 初始化本地存储returnservice;},);// 搜索历史服务:单例(依赖 StorageService)getIt.registerSingletonWithDependencies<SearchHistoryService>(()=>SearchHistoryService(getIt<StorageService>()),dependsOn:[StorageService],// 依赖 StorageService,确保先初始化);// --------------------------// 2. 状态管理层(Provider)注册// --------------------------// UserProvider:工厂模式(每次获取创建新实例,适合页面独立状态)getIt.registerFactory<UserProvider>(()=>UserProvider(getIt<StorageService>()),);// CartProvider:单例(全应用唯一,购物车状态全局共享)getIt.registerSingleton<CartProvider>(CartProvider(),);// ProductProvider:单例(商品数据全局共享)getIt.registerSingleton<ProductProvider>(ProductProvider(),);// SearchProvider:单例(依赖 SearchHistoryService)getIt.registerSingletonWithDependencies<SearchProvider>(()=>SearchProvider(getIt<SearchHistoryService>()),dependsOn:[SearchHistoryService],);}

关键知识点(必懂):

  • registerSingleton:单例模式,全局只有一个实例,适合全局共享的服务/状态(如 CartProvider、StorageService)
  • registerFactory:工厂模式,每次获取都会创建新实例,适合页面独立的状态(如 UserProvider)
  • registerSingletonAsync:异步单例,适合需要初始化的服务(如 StorageService 需要初始化 shared_preferences)
  • registerSingletonWithDependencies:带依赖的单例,确保依赖的服务先初始化

4️⃣ 重构服务层(Service),支持依赖注入

之前的服务是静态单例(紧耦合),现在重构为构造函数注入,彻底解耦!

① 重构 StorageService(lib/services/storage_service.dart)

import'package:shared_preferences/shared_preferences.dart';classStorageService{lateSharedPreferences_prefs;// 无参构造函数(供 DI 容器创建)StorageService();// 初始化方法Future<void>init()async{_prefs=awaitSharedPreferences.getInstance();}// 保存登录状态Future<void>saveLoginState(bool isLogin)async{await_prefs.setBool('is_login',isLogin);}// 获取登录状态boolgetLoginState(){return_prefs.getBool('is_login')??false;}// 其他存储方法...}

② 重构 SearchHistoryService(lib/services/search_history_service.dart)

import'package:shared_preferences/shared_preferences.dart';import'storage_service.dart';classSearchHistoryService{staticconstString_key='search_history';staticconstint _maxCount=20;finalStorageService_storageService;// 构造函数注入:依赖 StorageServiceSearchHistoryService(this._storageService);// 获取搜索历史List<String>getHistory(){return_storageService._prefs.getStringList(_key)??[];}// 添加搜索历史Future<void>addHistory(Stringkeyword)async{if(keyword.trim().isEmpty)return;List<String>history=getHistory();history.remove(keyword);history.insert(0,keyword);if(history.length>_maxCount)history.removeLast();await_storageService._prefs.setStringList(_key,history);}// 其他方法...}

5️⃣ 重构状态管理层(Provider),支持依赖注入

重构所有 Provider,通过构造函数注入所需服务,不再直接依赖具体实现!

① 重构 UserProvider(lib/providers/user_provider.dart)

import'package:flutter/foundation.dart';import'../services/storage_service.dart';classUserProviderextendsChangeNotifier{finalStorageService_storageService;bool _isLoggedIn=false;// 构造函数注入 StorageServiceUserProvider(this._storageService){// 初始化时从存储中获取登录状态_isLoggedIn=_storageService.getLoginState();}boolgetisLoggedIn=>_isLoggedIn;// 登录方法Future<void>login(Stringusername,Stringpassword)async{// 模拟登录逻辑if(username.isNotEmpty&&password.isNotEmpty){_isLoggedIn=true;await_storageService.saveLoginState(true);notifyListeners();}}// 退出登录方法Future<void>logout()async{_isLoggedIn=false;await_storageService.saveLoginState(false);notifyListeners();}}

② 重构 SearchProvider(lib/providers/search_provider.dart)

import'package:flutter/foundation.dart';import'../services/search_history_service.dart';import'../providers/product_provider.dart';import'../models/product.dart';classSearchProviderextendsChangeNotifier{finalSearchHistoryService_historyService;List<String>_historyList=[];List<Product>_resultList=[];String_keyword='';// 构造函数注入 SearchHistoryServiceSearchProvider(this._historyService);List<String>gethistoryList=>_historyList;List<Product>getresultList=>_resultList;Stringgetkeyword=>_keyword;// 加载搜索历史(依赖注入的服务)Future<void>loadHistory()async{_historyList=_historyService.getHistory();notifyListeners();}// 其他方法...}

其他 Provider 重构(CartProvider、ProductProvider)

按照上面的逻辑,给需要依赖的 Provider 添加构造函数注入,无需修改核心业务逻辑,只改依赖方式即可!


6️⃣ 改造 main.dart,初始化依赖注入

修改入口文件,先初始化依赖注入,再启动应用,确保所有服务、Provider 都能正常获取!

import'package:flutter/material.dart';import'package:provider/provider.dart';import'package:go_router/go_router.dart';import'di/injection.dart';import'router/app_router.dart';voidmain()async{WidgetsFlutterBinding.ensureInitialized();// 第一步:初始化依赖注入(必须在 runApp 之前)awaitinitInjection();runApp(constMyApp());}classMyAppextendsStatelessWidget{constMyApp({super.key});@overrideWidgetbuild(BuildContextcontext){returnMultiProvider(providers:[// 从 DI 容器中获取 Provider 实例ChangeNotifierProvider.value(value:getIt<UserProvider>()),ChangeNotifierProvider.value(value:getIt<CartProvider>()),ChangeNotifierProvider.value(value:getIt<ProductProvider>()),ChangeNotifierProvider.value(value:getIt<SearchProvider>()),],child:MaterialApp.router(title:'Flutter 鸿蒙电商 App',theme:ThemeData(primarySwatch:Colors.blue),routerConfig:appRouter,debugShowCheckedModeBanner:false,),);}}

7️⃣ 全局使用依赖注入(核心用法)

重构完成后,所有页面、组件中,无需手动创建实例,直接从 DI 容器中获取即可!

示例1:页面中使用 Provider

// 旧写法(紧耦合,手动创建)finaluserProvider=UserProvider(StorageService());// 新写法(松耦合,从 DI 容器获取)finaluserProvider=getIt<UserProvider>();

示例2:服务中使用依赖

// 旧写法(直接依赖静态方法)StorageService.saveLoginState(true);// 新写法(从 DI 容器获取服务)finalstorageService=getIt<StorageService>();awaitstorageService.saveLoginState(true);

示例3:路由守卫中使用

redirect:(context,state){// 从 DI 容器获取 UserProvider,无需手动注入finaluserProvider=getIt<UserProvider>();finalisLogin=userProvider.isLoggedIn;// 其他逻辑...}

🧪 鸿蒙真机测试验证

执行命令运行项目,验证依赖注入和模块化架构是否正常工作:

flutter clean flutter pub get flutter run

测试场景(全部通过才算成功):
✅ 依赖注入初始化成功,无报错
✅ 登录/退出登录正常,本地存储生效
✅ 搜索历史正常保存/删除,依赖服务正常
✅ 购物车状态全局共享,页面切换数据不丢失
✅ 鸿蒙真机运行流畅,无卡顿、无崩溃
✅ 新增页面/组件时,可直接从 DI 容器获取依赖,无需重复创建


⚠️ 鸿蒙开发常见坑解决(必看)

坑1:依赖注入初始化失败,报错“Instance not found”

  • 原因:依赖注册顺序错误,被依赖的服务后注册
  • 解决方案:使用dependsOn明确依赖关系,确保被依赖的服务先注册

坑2:Provider 无法获取,页面无状态

  • 原因:main.dart 中未通过ChangeNotifierProvider.value注入 DI 中的实例
  • 解决方案:确保所有 Provider 都在 MultiProvider 中注册,且使用getIt获取

坑3:异步服务初始化未完成,导致空指针

  • 原因:initInjection是异步方法,未等待完成就启动应用
  • 解决方案:在 main 函数中使用await initInjection(),确保初始化完成

坑4:模块化目录结构混乱,找不到文件

  • 解决方案:严格按照我们给出的目录结构搭建,导入路径要对应

坑5:鸿蒙设备上 DI 实例获取异常

  • 原因:get_it 版本过低,不兼容鸿蒙 Flutter 版本
  • 解决方案:升级 get_it 到 7.2.0 以上

📈 进阶优化方向(企业级必备)

  1. 添加接口抽象:给服务层添加抽象接口(如IStorageService),实现依赖倒置,更易测试
  2. 添加 mock 测试:使用 mockito 模拟依赖,编写单元测试
  3. 模块化拆分更细致:按功能拆分模块(如商品模块、用户模块、购物车模块)
  4. 添加依赖注入异常处理:防止获取不到实例导致崩溃
  5. 集成 get_it 代码生成:使用 get_it_generator 自动生成注册代码,减少手动操作
  6. 添加网络层依赖注入:将 Dio 网络请求注册到 DI 容器,统一管理

🎉 总结

到这里,我们完整实现了 Flutter 鸿蒙项目的 get_it 依赖注入 + 模块化架构优化!🎉

你已经拥有了:
✅ 一套企业级的模块化分层架构(DI层、服务层、状态层、页面层)
✅ get_it 依赖注入容器,实现类与类之间的彻底松耦合
✅ 单例/工厂模式灵活运用,合理管理实例生命周期
✅ 全项目代码重构,结构清晰、易维护、可扩展
✅ 鸿蒙真机完美适配,运行流畅无报错
✅ 具备大型项目开发能力,代码规范可直接用于竞赛、课程设计

这套架构不仅适用于鸿蒙项目,所有 Flutter 项目都能复用,学会它,你就超越了 80% 的 Flutter 初学者!

喜欢记得点赞关注,持续更新 Flutter 鸿蒙实战教程,带你从 0 到 1 打造企业级跨平台应用~😉

http://www.jsqmd.com/news/673423/

相关文章:

  • 告别内核自带驱动:深度折腾RTL8188EUS无线网卡,从编译到稳定上网的避坑全记录
  • 保姆级教程:用VMware 16 Pro在Windows电脑上免费体验macOS Monterey 12(附Darwin.iso工具下载)
  • 软件测试之基础篇(理论)
  • Flink状态存储选型实战:为什么生产环境更偏爱RocksDB?
  • GBFR Logs终极指南:如何用免费工具将你的《碧蓝幻想:Relink》战斗效率提升200%
  • Halcon模板匹配后怎么把结果画出来?手把手教你用vector_angle_to_rigid和affine_trans_contour_xld搞定轮廓显示
  • 革命性IoT开发工具dotnet/iot:一站式解决.NET物联网编程难题
  • 避坑指南:PCIe设备上电后Link Training失败的7个常见原因与排查思路
  • 从录音转文字到 AI 漫画生成:智在记录让知识真正 “活” 起来
  • 谈判力提升:技术人薪资博弈
  • 雀魂牌谱屋完整指南:3个技巧快速提升麻将数据分析能力
  • 《简单了解并构建LangChain》
  • jQuery 遍历
  • EM 24ai 运维必知:一招搞定用户密码重置!
  • Golang Redis Pipeline如何用_Golang Redis Pipeline教程【完整】
  • 从零学习Kafka:ZooKeeper vs KRaft
  • 告别PS!Mulimg Viewer图像拼接保姆级教程:从实验数据到期刊级Figure全流程
  • 深开鸿的开源鸿蒙OS,能不能用云固件的模式来快速安装?超多截图,有故事。第一集,故事未完,还有第二集。
  • 零基础玩转all-MiniLM-L6-v2:5分钟搞定语义搜索环境搭建
  • 如何利用backdoor-apk实现安卓应用的远程控制
  • 谢菲尔德大学发现极限压缩AI模型时,初始化才是真正的拦路虎
  • 制造业、质检类20种业务场景,SQL精写技巧
  • 从理论到代码:我是如何复现EVO的ATE/RPE计算并与官方结果对齐的(含避坑点)
  • 从宁德新能源面试官视角,拆解Halcon/OpenCV工程师的硬核技能树(附避坑指南)
  • Workrave终极指南:告别重复性劳损的完整解决方案
  • DebateLab-个人博客(1)后端总体架构与比赛状态机设计
  • 魔兽争霸3终极优化指南:如何用WarcraftHelper解决老游戏兼容性问题
  • C语言学习笔记5
  • 3分钟学会ncmdump:终极网易云音乐NCM文件解密转换指南
  • Go语言如何做协程调度_Go语言协程调度原理教程【实用】