鸿蒙Flutter 依赖注入模式:使用Provider管理服务类

📅 2026/7/20 20:03:24 👁️ 阅读次数 📝 编程学习
鸿蒙Flutter 依赖注入模式:使用Provider管理服务类


一、依赖注入概述

依赖注入(Dependency Injection,简称DI)是一种软件设计模式,用于实现控制反转(Inversion of Control,简称IoC)。在Flutter开发中,依赖注入可以帮助我们:

  • 解耦组件:组件不直接创建依赖,降低耦合度
  • 提高可测试性:方便替换为mock对象进行测试
  • 简化维护:集中管理依赖,易于维护和替换
  • 实现复用:同一个服务可以在多个组件中复用

Provider不仅可以用于状态管理,还可以作为依赖注入容器,管理服务类的生命周期。

二、创建服务类

在使用Provider进行依赖注入之前,我们需要先创建服务类。服务类通常是无状态的工具类,提供特定的功能。

2.1 日志服务

classLogService{voidinfo(Stringmessage){debugPrint('[INFO]$message');}voiderror(Stringmessage,[Object?error]){debugPrint('[ERROR]$message:$error');}}

2.2 存储服务

classStorageService{String_data='';Future<void>saveData(Stringdata)async{awaitFuture.delayed(constDuration(milliseconds:100));_data=data;}Future<String>loadData()async{awaitFuture.delayed(constDuration(milliseconds:100));return_data;}}

2.3 API服务

classApiService{Future<Map<String,dynamic>>fetchProduct(Stringid)async{awaitFuture.delayed(constDuration(seconds:1));return{'id':id,'name':'商品$id','price':99.9,};}}

三、使用Provider注入服务

使用Provider注入服务非常简单,只需要在MultiProvider中声明即可:

MultiProvider(providers:[Provider<LogService>(create:(_)=>LogService()),Provider<StorageService>(create:(_)=>StorageService()),Provider<ApiService>(create:(_)=>ApiService()),ChangeNotifierProvider(create:(context)=>DataProvider(logService:context.read<LogService>(),storageService:context.read<StorageService>(),),),],child:constMyApp(),)

3.1 注入不可变服务

对于无状态的服务类,使用Provider即可:

Provider<LogService>(create:(_)=>LogService())

3.2 注入可变状态

对于需要管理状态的类,使用ChangeNotifierProvider

ChangeNotifierProvider(create:(context)=>DataProvider(logService:context.read<LogService>(),storageService:context.read<StorageService>(),),)

四、在Provider中使用依赖

在ChangeNotifier中使用依赖注入的服务:

classDataProviderextendsChangeNotifier{finalLogService_logService;finalStorageService_storageService;String_data='初始数据';DataProvider({requiredLogServicelogService,requiredStorageServicestorageService,}):_logService=logService,_storageService=storageService;Stringgetdata=>_data;Future<void>updateData(StringnewData)async{_logService.info('更新数据:$newData');_data=newData;await_storageService.saveData(newData);notifyListeners();}Future<void>loadData()async{_logService.info('加载数据');_data=await_storageService.loadData();notifyListeners();}}

五、在Widget中使用服务

在Widget中使用依赖注入的服务:

5.1 获取服务

classProductDetailPageextendsStatelessWidget{constProductDetailPage({super.key});@overrideWidgetbuild(BuildContextcontext){finallogService=context.read<LogService>();returnScaffold(appBar:AppBar(title:constText('商品详情')),body:Center(child:ElevatedButton(onPressed:(){logService.info('用户点击加入购物车');context.read<CartProvider>().addItem('1','商品',19.9);},child:constText('加入购物车'),),),);}}

5.2 注意事项

  • 使用context.read<T>()获取不需要监听的服务
  • 使用context.watch<T>()获取需要监听变化的状态
  • 服务必须在当前Provider之前声明
  • 依赖注入的服务默认是单例

六、单例服务与工厂模式

6.1 Provider默认创建单例

Provider默认创建单例实例,整个应用中只创建一次:

MultiProvider(providers:[Provider(create:(_)=>ApiService()),],child:constMyApp(),)

6.2 使用Provider.value

如果需要传入已存在的实例,可以使用Provider.value

finalapiService=ApiService();MultiProvider(providers:[Provider.value(value:apiService),],child:constMyApp(),)

6.3 延迟初始化

使用ProxyProvider进行延迟初始化,只有在需要时才创建Provider:

MultiProvider(providers:[Provider(create:(_)=>ApiService()),ChangeNotifierProxyProvider<ApiService,CartProvider>(create:(context)=>CartProvider(apiService:context.read()),update:(context,apiService,cartProvider){returncartProvider!..updateApiService(apiService);},),],child:constMyApp(),)

七、依赖注入的优势

优势说明
解耦组件不直接创建依赖,降低耦合
可测试方便替换为mock对象进行测试
可维护集中管理依赖,易于维护
可复用同一个服务可以在多个组件中复用
生命周期管理Provider自动管理服务生命周期

八、最佳实践

8.1 将服务类与状态类分离

服务类应该是无状态的工具类,状态类应该只负责管理状态:

// 服务类 - 无状态classApiService{Future<User>fetchUser(Stringid)async{...}}// 状态类 - 管理状态classUserProviderextendsChangeNotifier{finalApiService_apiService;User?_user;UserProvider({requiredApiServiceapiService}):_apiService=apiService;}

8.2 使用Provider注入不可变服务

对于无状态的服务,使用Provider而不是ChangeNotifierProvider

Provider<LogService>(create:(_)=>LogService())

8.3 使用ChangeNotifierProvider管理可变状态

对于需要管理状态的类,使用ChangeNotifierProvider

ChangeNotifierProvider(create:(_)=>CartProvider())

8.4 按依赖顺序声明Provider

依赖其他Provider的Provider必须在被依赖的Provider之后声明:

MultiProvider(providers:[Provider<ApiService>(create:(_)=>ApiService()),// CartProvider依赖ApiService,必须在ApiService之后ChangeNotifierProvider(create:(context)=>CartProvider(apiService:context.read()),),],child:constMyApp(),)

8.5 在构造函数中注入依赖

不要在方法中直接使用context.read,而是在构造函数中注入依赖:

classCartProviderextendsChangeNotifier{finalApiService_apiService;// 正确:在构造函数中注入CartProvider({requiredApiServiceapiService}):_apiService=apiService;voidfetchProducts(){// 使用注入的依赖_apiService.fetchProducts();}}

九、代码示例

9.1 创建一个依赖注入演示页面

classDependencyInjectionPageextendsStatelessWidget{constDependencyInjectionPage({super.key});@overrideWidgetbuild(BuildContextcontext){returnMultiProvider(providers:[Provider<LogService>(create:(_)=>LogService()),Provider<StorageService>(create:(_)=>StorageService()),ChangeNotifierProvider(create:(context)=>DataProvider(logService:context.read<LogService>(),storageService:context.read<StorageService>(),),),],child:Scaffold(appBar:AppBar(title:constText('依赖注入模式演示')),body:ListView(padding:constEdgeInsets.all(16),children:[_buildSection('服务类定义',_serviceDefinition()),_buildSection('依赖注入演示',_diDemo()),_buildSection('在Provider中使用依赖',_providerWithDependencies()),_buildSection('依赖注入优势',_diAdvantages()),],),),);}Widget_buildSection(Stringtitle,Widgetcontent){returnCard(margin:constEdgeInsets.only(bottom:16),child:Padding(padding:constEdgeInsets.all(16),child:Column(crossAxisAlignment:CrossAxisAlignment.start,children:[Text(title,style:constTextStyle(fontSize:18,fontWeight:FontWeight.bold)),constSizedBox(height:12),content,],),),);}Widget_diDemo(){returnColumn(children:[Consumer<DataProvider>(builder:(context,provider,child){returnText('当前数据:${provider.data}',style:constTextStyle(fontSize:18),);},),constSizedBox(height:16),TextField(decoration:constInputDecoration(labelText:'输入新数据'),onSubmitted:(value){context.read<DataProvider>().updateData(value);},),constSizedBox(height:16),ElevatedButton(onPressed:()=>context.read<DataProvider>().updateData('Hello DI!'),child:constText('设置Hello'),),],);}}

9.2 代码解析

在这个演示页面中:

  1. 服务类定义:展示了LogService、StorageService等服务类的定义方式
  2. 依赖注入演示:展示了如何使用MultiProvider注入多个服务
  3. 在Provider中使用依赖:展示了如何在DataProvider中使用注入的服务
  4. 依赖注入优势:总结了依赖注入的优势

十、关键要点

10.1 Provider可作为依赖注入容器使用

Provider不仅可以管理状态,还可以管理服务类的生命周期。

10.2 使用Provider注入不可变服务

对于无状态的服务类,使用Provider即可,不需要使用ChangeNotifierProvider

10.3 Provider默认创建单例实例

Provider默认创建单例实例,整个应用中只创建一次。

10.4 服务之间可以有依赖关系

一个Provider可以依赖其他Provider,但必须按依赖顺序声明。

10.5 便于测试和维护

使用依赖注入可以方便地替换为mock对象进行测试,同时也便于维护和扩展。

十一、总结

依赖注入是一种重要的软件设计模式,可以帮助我们解耦组件、提高可测试性和可维护性。在Flutter中,Provider不仅可以用于状态管理,还可以作为依赖注入容器使用。

在实际开发中,建议遵循以下原则:

  1. 将服务类与状态类分离
  2. 使用Provider注入不可变服务
  3. 使用ChangeNotifierProvider管理可变状态
  4. 按依赖顺序声明Provider
  5. 在构造函数中注入依赖,不要直接使用context.read

希望本文能帮助你掌握依赖注入模式的使用,并在实际项目中正确应用!