Flutter社区的一个library: get_it
视频介绍:Flutter Dependency Injection For Beginners | Complete Guide
视频对应的博文 :Dependency Injection in Flutter
官网的介绍:
Simple direct Service Locator that allows to decouple the interface from a concrete implementation and to access the concrete implementation from everywhere in your App
关于什么是Service Locator:
If you are not familiar with the concept of Service Locators, its a way to decouple the interface (abstract base class) from a concrete implementation and at the same time allows to access the concrete implementation from everywhere in your App over the interface. I can only highly recommend to read this classic article by from Martin Fowler Inversion of Control Containers and the Dependency Injection pattern
所以Service Locator
可以将接口(抽象基类)与具体实现分离,同时允许通过接口从App中的任何位置访问具体实现。
对于依赖注入不是很了解的同学可以参考:
为什么要使用get_it
我们也可以通过其他的方式在app中的任意位置获取到要访问的对象,但是:
- 如果使用Singleton,则无法轻松地将实现切换到另一个(例如用于单元测试的模拟版本)
- 用于依赖项注入的IoC容器提供了类似的功能,但代价是启动时间慢且可读性差,因为您不知道神奇注入的对象来自何处。 由于大多数IoC库都依赖反射,因此它们不能与Flutter一起使用。
使用场景
- 访问诸如REST API客户端,数据库之类的服务对象,以便可以轻松模拟它们
- 从Flutter视图访问View / AppModels / Manager
- 由于接口和实现是分离的,因此您还可以在不同的实现中注册Flutter Views,并在启动时确定要使用的视图,例如 取决于屏幕分辨率
使用注意事项
按照官方解释:始终使用相同的样式将项目文件作为相对路径或我建议的包导入。 不要混用它们,因为虽然两种导入方式都引用相同的文件,但目前Dart将以不同方式导入的类型视为两种不同的类型。
比如我们在lib根目录下新建了一个Service Locator,我们要在不同的文件中使用,可以使用以下两种方式导入,官方的意思是应该一直使用同一种方式导入。
那么如果真的混合使用,会有什么影响吗?我试过在不同的文件中使用不同的导入方式混用,但没发现异常,且locator对象本来就是一个单例的,
知道的人可以告诉一下我,?
import '../../locator.dart';
import 'package:provider_architecture/locator.dart';
如何使用
- 获取GetIt对象
GetIt getIt = GetIt.instance;
//There is also a shortcut (if you don't like it just ignore it):
GetIt getIt = GetIt.I;
- 注册
sl.registerSingleton<AppModel>(AppModelImplementation());
sl.registerLazySingleton<RESTAPI>(() =>RestAPIImplementation());
// if you want to work just with the singleton:
GetIt.instance.registerSingleton<AppModel>(AppModelImplementation());
GetIt.I.registerLazySingleton<RESTAPI>(() =>RestAPIImplementation());
- 获取服务对象
var myAppModel = sl.get<AppModel>();
var myAppModel = sl<AppModel>();
// as Singleton:
var myAppModel = GetIt.instance<AppModel>();
var myAppModel = GetIt.I<AppModel>();
- 注册的种类
- Factory工厂模式
void registerFactory<T>(FactoryFunc<T> func)
locator.registerLazySingleton(() => Api());
locator.registerFactory(() => HomeModel());
传入参数是一个函数func,这个func函数要返回一个实现了类型T的对象,每次调用获取对象的方式时,都会返回一个新对象
- 单例模式&懒加载单例
单例注册时,传入一个范型T的对象或其子类的对象,如果创建这个单例时是耗时的,那么可以不在app启动的时候注册,而放到第一次使用到该服务的时候,即使用懒加载的方式。
void registerSingleton<T>(T instance)
void registerLazySingleton<T>(FactoryFunc<T> func)
一个例子:
在app启动的时候调用注册方法
void main() {
setupLocator();
runApp(MyApp());
}
注册方法内部细节
单独的locator.dart文件:
GetIt locator = GetIt.instance;
void setupLocator() {
locator.registerLazySingleton(() => Api());
}
在数据类中使用服务
Api _api = locator<Api>();
List<Comment> comments;
Future fetchComments(int postId) async {
...
comments = await _api.getCommentsForPost(postId);
...
}