Fluttin

一个为 Flutter 开发者设计的实用轻量级依赖注入框架。

入门

这是 koin 的 Flutter 版本,在用法上与原始的 koin 基本相同。只是 Dart 的闭包不支持接收者类型,所以在该类中看起来有点复杂,但原理是相同的。关于 DI 的概念,请参考 koin 官方网站:https://insert-koin.io/

您需要在项目开始时执行 startFluttin。

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);
  @override
  State<StatefulWidget> createState() {
    return MyAppState();
  }
}

class MyAppState extends State<MyApp> {

  @override
  void initState() {
    super.initState();
    initFluttin();
  }

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }

  Future<void> initFluttin() async {
    startFluttin((FluttinApplication application) {
      application.modules(<Module>[
        Modules.module,
        Modules.screenModule,
        Modules.serviceModule,
        Modules.dbModule,
      ]);
    });
  }
}

然后在 libs/ 中创建 modules.dart

class Modules {
  static Module module = module((Module module) {
    module.factory((Scope scope, DefinitionParameters parameters) =>
        MyGameRepository(
            scope.get(), scope.get(), scope.get(), scope.get(), scope.get()));
  });

  static Module screenModule = module((Module module) {
    module.scope<ScreenScope>((scopeSet) {});
  });

  static Module serviceModule = module((Module module) {
    module.single((Scope scope, DefinitionParameters parameters) =>
        ServiceManager.instance);
    module.single((Scope scope, DefinitionParameters parameters) =>
        scope.get<ServiceManager>().gatewayService);
  });

  static Module dbModule = module((Module module) {
    module.single(
        (Scope scope, DefinitionParameters parameters) => DBUtils.appDatabase);
    module.single((Scope scope, DefinitionParameters parameters) =>
        scope.get<AppDatabase>().screenDao);
  });
}

您无需关注此类中其他类的生成方式

class MyGameRepository {
  MyGameRepository(this._appInfoDao, this._downloadPackageDao,
          this._taskInfoDao, this._userAppDao, this._appVirtualDao);

  final AppInfoDao _appInfoDao;
  final DownloadPackageDao _downloadPackageDao;
  final DownloadTaskDao _taskInfoDao;
  final UserAppDao _userAppDao;
  final AppVirtualDao _appVirtualDao;
  
}

以下是一个简单的说明

  • 如果您想使用它,您可以直接使用 inject() 来生成它

class _XXState extends State<XXWidget> {
  MyGameRepository _myGameRepository = inject();
    @override
    Widget build(BuildContext context) {
        return Scaffold();
    }
}
  • 如果您想编写一个模块,有几种提供它的方式

    • factory: 每次 inject() 都会生成一个新实例。
    • single: 只有第一次 inject() 会生成新实例,之后将使用首次生成的实例。这相当于单例的概念。
    • scoped: 当满足作用域条件时,只有第一次 inject() 会生成新实例,之后会重复使用。例如:scope=UserScope,这意味着当用户登录时,从 inject() 输出的实例是相同的,当用户注销后再次登录时,会再次尝试生成新实例。可以理解为用户登录时的单例。
  • 如果我想生成的类中会用到其他类

    • scope.get()

        module.factory((Scope scope, DefinitionParameters parameters) =>
          MessageScreenCubit(scope.get(), scope.get());
  • 如果我想动态传入参数

    • DefinitionParameters

      messageScreenCubit = inject(parameters: () {
        return DefinitionParameters(values: [
          widget.conversation,
          widget.conversationId,
          widget.targetUserId,
        ]);
      });

      module.factory((Scope scope, DefinitionParameters parameters) {
        return MessageScreenCubit(conversation: parameters[0],
                conversationId: parameters[1],
                userId: parameters[2],
                );
      });
  • 如果我想在模块中为接口提供不同的实现

    • qualifier

      class _XXState extends State<XXWidget> {
        Animal animal = inject(qualifier: StringQualifier('dog'));
      
        @override
        Widget build(BuildContext context) {
            return Scaffold();
          }
        }

      module.factory<Animal>(
        (Scope scope, DefinitionParameters parameters) => Dog(),
        qualifier: StringQualifier('dog')
      );
      module.factory<Animal>(
        (Scope scope, DefinitionParameters parameters) => Cat(),
        qualifier: StringQualifier('cat')
      );

GitHub

查看 Github