Kinject (Dependency Injection)

It is a simple wrapper on Inherited Widget.

Single instance injection

To provide just a single instance to a widget tree you can use Kinject widget.

Kinject(
  factory: (context) => const LoginBloc(),
  builder: (context) {
    return Scaffold(
      body: SafeArea(
      child: Center(
        child: ElevatedButton(
        onPressed: context.resolve<LoginBloc>().login,
        child: const Text('Log in'),
              ),
            ),
          ),
        );
    },
);

Multi-instance injection and inter-dependency

To provide multiple instances and provide dependency between them ProxyInject class and Kinjects widget can be used.


class LoginPage extends StatelessWidget {
  const LoginPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Kinjects(
      kinjects: [
        ProxyKinject<AuthDataSource>((_) => AuthDataSourceImpl()),
        ProxyKinject<AuthRepository>(
          (context) => AuthRepositoryImpl(
            context.resolve<AuthDataSource>(),
          ),
        ),
        ProxyKinject<LoginBloc>(
          (context) => LoginBloc(
            context.resolve<AuthRepository>(),
          ),
        ),
      ],
      builder: (context) {
        return Scaffold(
          body: SafeArea(
            child: Center(
              child: ElevatedButton(
                onPressed: context.resolve<LoginBloc>().login,
                child: const Text('Log in'),
              ),
            ),
          ),
        );
      },
    );
  }
}

Singleton and Factory initialization

Kinject gives flexibility to a developer to adjust instance as Singleton or Factory. If you want to initialize Singleton class for all app, you can provide instance of this class above the MaterialApp. Or, if you want to initialize instance as factory, you can adjust it with the help of subtrees based providing.

KinjectModule for modular architecture

KinjectModule is a class that can be used to provide instances for a specific module. It is useful for modular architecture, where you can provide instances for a specific module.

class LoginModule extends KinjectModule {
  const LoginModule({super.key});

  @override
  List<ProxyKinject> binds(BuildContext context) {
    return [
      ProxyKinject<AuthDataSource>((_) => AuthDataSourceImpl()),
      ProxyKinject<AuthRepository>(
            (context) => AuthRepositoryImpl(
          context.resolve<AuthDataSource>(),
        ),
      ),
      ProxyKinject<LoginBloc>(
            (context) => LoginBloc(
          context.resolve<AuthRepository>(),
        ),
      ),
    ];
  }

  @override
  Widget child(BuildContext context) {
    return const LoginPageV2();
  }
}

KinjectObserver

You can enable KinjectObserver for your app to track initialize and dispose events.

At first, you should configure your own subclass:

final class AppKinjectObserver implements KinjectObserver {
  @override
  void onCreate(Kinject instance) {
    debugPrintThrottled('${instance.type} initialized');
  }

  @override
  void onDispose(Kinject instance) {
    debugPrintThrottled('${instance.type} disposed');
  }
}

And, with the help of the following command, you can configure observer:

Kinject.observer = AppKinjectObserver();

Maintainers

Kanan Yusubov

Libraries

kinject