패키지, 저장소 및 앱 카테고리 검색

패키지 상세v3.0.1

flutter_getit

'get_it'와의 통합을 통해 Flutter 프로젝트 종속성을 효율적으로 관리하며, 강력한 페이지 제어, 라우팅 관리 및 모듈 유연성을 제공합니다.

AndroidiOSWebmacOSWindowsLinux
30일 다운로드
1.3천
좋아요
91
Pub 점수
140

패키지 설치

flutter pub add flutter_getit

패키지 개요

공개 정보를 바탕으로 생성한 선택 가이드입니다.

Flutter_GetIt는 Flutter 애플리케이션에서 종속성을 관리하는 것을 간소화하는 의존성 주입 패키지입니다. 효율적인 서비스 및 위젯 인스턴스화를 가능하게 하며, 모듈식 아키텍처를 지원하고 라우팅 및 페이지 관리와 원활하게 통합됩니다. GetIt의 가볍고 유연한 API를 활용하여 개발자는 앱의 다양한 모듈에서 종속성을 쉽게 등록하고 해결할 수 있습니다. 이 패키지는 코드의 유지보수성과 테스트 가능성을 향상시켜 확장 가능한 Flutter 프로젝트에 이상적입니다.

사용 사례

  • 앱 범위의 서비스 관리
  • 위젯에 종속성 주입하기
  • 모듈러 앱 아키텍처 지원
  • 단위 및 위젯 테스트 간소화
  • 동적 종속성 해결 활성화
  • 경로 및 페이지 탐색 촉진

주요 기능

  • 경량이고 사용하기 쉬운 API
  • 지연 및 즉시 서비스 등록을 지원
  • Flutter 위젯 트리와 통합
  • 명확한 종속성 라이프사이클 제어를 제공
  • 의존성 해결을 위한 디버깅 도구를 제공합니다
  • 여러 플랫폼과 호환됩니다

적합한 대상

  • 중대규모의 Flutter 애플리케이션
  • 모듈러 개발을 사용하는 팀
  • 관심사의 명확한 분리가 필요한 프로젝트
  • 테스트 가능성을 우선시하는 개발자
  • 복잡한 종속성 체인을 가진 앱

고려 사항

  • 고급 구성은 수동 설정이 필요합니다
  • 제한된 내장 상태 관리
  • 의존성이 거의 없는 매우 작은 앱에는 적합하지 않음
  • 완전한 라우팅 통합을 위해서는 추가 패키지가 필요할 수 있습니다
  • 디버깅 문제를 해결하려면 종속성 그래프에 대한 이해가 필요합니다

원본 README

연결된 소스 저장소의 README 원문 스냅샷입니다. 최신 내용은 저장소에서 확인하세요.

Flutter GetIt

Languages:

Portuguese English

This package is an essential tool for efficient dependency management in your Flutter project's lifecycle. It offers robust support for page control, including route management and the flexibility to work with modules.

Key Features:

Dynamic Dependency Control: Utilizing the powerful get_it mechanism, this package automatically registers and removes dependencies as needed, optimizing performance and ensuring your application's efficiency.

Flexible Modules: Take advantage of your code's modularity. This package makes it easy to create and manage modules, keeping your project organized and easy to maintain.

Additional Benefits:

Automatic Dependency Cleanup: The package automatically removes dependencies when they are no longer needed, ensuring efficient resource management for your application.

Flutter GetIt offers various approaches to controlling routes and loading your application's bindings, including page routes, builders, and modules. You will see details of each of them later on.

Getting Started

Configuring flutter_getit

Setting up Flutter GetIt is done by adding a widget around your MaterialApp. By including the widget and implementing the builder attribute, three attributes will be passed to you:

Field Description
context BuildContext
routes A map that should be added to the routes tag of the MaterialApp or CupertinoApp
isReady This attribute indicates whether all asynchronous middlewares and bindings have been loaded

The [routes] attribute should be passed to the MaterialApp, as illustrated in the example below:

import 'package:flutter/material.dart';
import 'package:flutter_getit/flutter_getit.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return FlutterGetIt(
      modulesRouter: [
        FlutterGetItModuleRouter(
          name: '/Initialize',
          pages:[
            FlutterGetItPageRouter(
              name: '/Landing',
              builder: (context) => const Scaffold(
                body: Center(
                  child: Text('Initializing...'),
                ),
              ),
            ),
          ]
        ),
      ],
      builder: (context, routes, isReady) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
            useMaterial3: true,
          ),
          initialRoute: '/Landing/Initialize',
          routes: routes,
          builder: (context, child) => switch (isReady) {
            true => child ?? const SizedBox.shrink(),
            false => const WidgetLoadDependencies(),
          },
        );
      },
    );
  }
}

The example above demonstrates the basic configuration of FGetIt, including handling loading (loader) in asynchronous middlewares and bindings. Further down, we will detail each of these items.

Important: Flutter GetIt does not replace Flutter's standard routes; it leverages the existing structure using Flutter's native lifecycle. This approach keeps the application's navigation intact, avoiding unnecessary rewrites and preventing bugs and unwanted issues.

However, for it to control dependencies, you must register your application's pages in the [modulesRouter] attribute as shown in the example above, [pagesRouter], or [modules], which you will see a little further on.

FlutterGetItModuleRouter

In the example above, you saw the simplest way to implement a route within flutter_getit. If your page is as simple as our initial page, you can use the page class, adding the page and the path it will respond to.

The first level of the route is [FlutterGetItModuleRouter], which is responsible for grouping the routes of a specific area of the application, such as the authentication area, the products area, the settings area, etc.

[FlutterGetItModuleRouter] consists of a [name] and [pages], where [name] is the name of the module and [pages] is a list of [FlutterGetItPageRouter] or other [FlutterGetItModuleRouter].

You can think of [FlutterGetItModuleRouter] as a "Module" or "Sub-Module" within the routing system, allowing you to create as many modules as you want and nest them.

They are passed hierarchically to the child module or page, allowing you to navigate within the tree, and if necessary, FlutterGetIt will instantiate the Binds.

Let's look at an example of how to create a [FlutterGetItModuleRouter]:

FlutterGetItModuleRouter(
    name: '/Register',
    bindings: [
      Bind.lazySingleton<RegisterController>(
        (i) => RegisterController(),
      ),
    ],
    onInit: (i) => debugPrint('hi by /Register'),
    onDispose: (i) => debugPrint('bye by /Register'),
    pages: [
      FlutterGetItPageRouter(
        name: '/Page',
        builder: (context) => RegisterPage(
          controller: context.get(),
        ),
        bindings: [
          Bind.lazySingleton<RegisterController>(
            (i) => RegisterController(),
          ),
        ],
      ),
      FlutterGetItModuleRouter(
        name: '/ActiveAccount',
        bindings: [
          Bind.lazySingleton<ActiveAccountPageDependencies>(
            (i) => (
              controller: ActiveAccountController(name: 'MyName'),
              validateEmailController:
                  ValidateEmailController(email: 'fgetit@injector'),
            ),
          ),
        ],
        pages: [
          FlutterGetItPageRouter(
            name: '/Page',
            builder: (context) => const ActiveAccountPage(),
            bindings: [],
          ),
        ],
      ),
    ],
  ),

In the structure above, the [FlutterGetItModuleRouter] [/Register] has a page [/Page] and a submodule [/ActiveAccount], which in turn has a page [/Page]. If you decide to navigate to [/ActiveAccount/Page], [FlutterGetIt] will instantiate the dependencies of [/ActiveAccount] and [/ActiveAccount/Page] and also of [/Register], as it is a superior [FlutterGetItModuleRouter] in the same tree as [/ActiveAccount].

A [FlutterGetItModuleRouter] can have as many pages and submodules as desired and can be nested with other [FlutterGetItModuleRouter]. The attributes of this component are:

Attribute Description
name Module name.
bindings Binds that will be instantiated and removed in the same lifecycle as the [module] used.
onDispose Here you can execute an action before the Binds are closed and removed.
onInit Here you can execute an action before the Binds are instantiated.
pages Pages or submodules that will be instantiated and removed in the same lifecycle as the [module] used.

FlutterGetItPageRouter

[FlutterGetItPageRouter] is the component responsible for creating a page route within your application. It consists of a [name], which is the path of the route, and a [builder], which is the widget that will be displayed on the screen and also has [Binds] to initialize and [pages] if you want to create a hierarchical navigation tree.

FlutterGetItPageRouter(
          name: '/Landing',
          builder: (context) => const Scaffold(
            body: Center(
              child: Text('Initializing...'),
            ),
          ),
        ),

In the example above, we created a route called [/Landing] that will display the text "Initializing..." at the center of the screen.

[FlutterGetItPageRouter] also has a [bindings] attribute, which is a list of [Bind] that will be instantiated and removed in the same lifecycle as the [page] used.

FlutterGetItPageRouter(
          name: '/Landing/Initialize',
          builder: (context) => const Scaffold(
            body: Center(
              child: Text('Initializing...'),
            ),
          ),
          bindings: [
             Bind.lazySingleton(
              (i) => InitializeController(),
            )
          ],
        ),

In this way, flutter_getit will add, during your screen's loading, an instance of InitializeController to get_it, enabling the use of your page. However, it is important to note that when leaving this screen, flutter_getit will remove the instance from your application's memory, ensuring efficient resource management.

[FlutterGetItPageRouter] also has a [buildAsync] method that will be invoked when any asynchronous binding or middleware is found on this route.

Application Dependencies

Every project requires dependencies that need to remain active throughout the application, such as RestClient (Dio), Log, and many others. For FlutterGetIt, you can easily make these available. During the initialization of [FlutterGetIt], simply pass the [bindings] parameter within [FlutterGetIt] in the main function.

Example using [bindings]

FlutterGetIt(
      bindings: MyApplicationBindings(),
      builder: (context, routes) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
            useMaterial3: true,
          ),
          initialRoute: '/Landing/Initialize',
          routes: routes,
        );
      },
    );

The [MyApplicationBindings] class extends [ApplicationBindings], as shown in the example below.

class MyApplicationBindings extends ApplicationBindings {
  @override
  List<Bind<Object>> bindings() => [
        Bind.singletonAsync(
          (i) async => SharedPreferences.getInstance(),
        ),
      ];
}

[modules] Attribute

In large projects, the list of application dependencies can be extensive. To keep the project more organized, we created FlutterGetItModule, which should be applied to the "modules" attribute. With it, you can provide a class for loading your dependencies and apply initialization rules, similar to routes.

 FlutterGetIt(
      modules: [
        LandingModule(),
      ],
      builder: (context, routes) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
            useMaterial3: true,
          ),
          initialRoute: '/Landing/Initialize',
          routes: routes,
        );
      },
    );
How to Create a Module:
class LandingModule extends FlutterGetItModule {
  @override
  String get moduleRouteName => '/Landing';

  @override
  List<Bind<Object>> get bindings => [];

  @override
  List<FlutterGetItModuleRouter> get pages => [
    FlutterGetItModuleRouter(
          name: '/Initialize',
          bindings: [],
          pages: [
            FlutterGetItPageRouter(
              name: '/Page',
              page: (context) => const InitializePage(),
              bindings: [
                Bind.lazySingleton<InitializeController>(
                      (i) => InitializeController(),
                ),
              ],
            ),
          ]
        ),
    FlutterGetItModuleRouter(
          name: '/Presentation',
          bindings: [], 
            pages: [
              FlutterGetItPageRouter(
                name: '/Page',
                page: (context) => const InitializePage(),
                bindings: [
                  Bind.lazySingleton<InitializeController>(
                        (i) => InitializeController(),
                  ),
                ],
              ),
            ]
        ),
        FlutterGetItPageRouter(
          name: '/Simple',
          page: (context) => const InitializePage(),
          bindings: [
            Bind.lazySingleton<InitializeController>(
                  (i) => InitializeController(),
            ),
          ],
        ),
      ];

  @override
  void onDispose(Injector i) {}

  @override
  void onInit(Injector i) {}
}

About [moduleRouteName]:

  • This is the name of your module; your routes should start with this key and end with the key of an existing internal route in [pages].

About [bindings]:

  • This is where your module's "global" bindings are placed, such as repositories. Whenever a module route is called, these bindings will be checked and instantiated if necessary.

About [pages]:

  • This is where your module's internal pages are defined, following the same rules mentioned above about [FlutterGetItModuleRouter]. It is important to note that the order of the list does not affect usage.

About [onInit] and [onDispose]:

  • These will be called at the initialization and disposal of the module (entry and exit), which can be any within [pages].

Retrieving an Instance

There are two ways to retrieve an instance from flutter_getit. One is through the [Injector] class, and the other is through an extension added to BuildContext using [context.get].

Injector.get<ServiceForApplication>();

// or

context.get<ServiceForApplication>();
Example Using [context.get]
class HomePage extends StatelessWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context) {
    // Calling the BuildContext extension
    var service = context.get<ServiceForApplication>();
    return ...;
  }
}
Example Using Injector
class HomePage extends StatelessWidget {
  final service = Injector.get<ServiceForApplication>();
  HomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return ...;
  }
}
  • You can also use [Injector.getAsync] for asynchronous Binds; see more about them below.

Here's the translation of the provided text:

Bind Types

Flutter_getit supports all other bindings supported by the get_it engine:

Here is the table formatted in Markdown:

Bind Description
Bind.lazySingleton This bind will initialize the dependency only when the user calls it for the first time. After that, it will become a singleton, returning the same instance every time it is requested.
Bind.lazySingletonAsync This bind works like Bind.lazySingleton, but its first call will be asynchronous.
Bind.singleton Unlike lazySingleton, singleton will initialize the instance immediately when the page loads.
Bind.singletonAsync This bind works like Bind.singleton, but its first call will be asynchronous.
Bind.factory A factory ensures that every time you request an instance from the dependency manager, it will provide a new instance.
Bind.factoryAsync This bind works like Bind.factory, but its first call will be asynchronous.

[keepAlive] Attribute

  • The keepAlive attribute, present in bindings, instructs FlutterGetIt not to discard the class, keeping it in memory throughout the application's lifecycle.

It's important to use this parameter cautiously and only when you are absolutely sure of what you are doing.

Complete Example

class MyApplicationBindings extends ApplicationBindings {
  @override
  List<Bind<Object>> bindings() => [
        Bind.singleton(
          (i) async => SharedPreferences.getInstance(),
        ),
        Bind.singletonAsync(
          (i) async => SharedPreferences.getInstance(),
        ),
        Bind.lazySingleton(
          (i) async => AsyncTest(),
        ),
        Bind.lazySingletonAsync(
          (i) async => Future.delayed(
            const Duration(seconds: 4),
            () => AsyncTest(),
          ),
        ),
        Bind.factory(
          (i) => MyDeepLink(),
        ),
        Bind.factoryAsync(
          (i) => Future.delayed(
            const Duration(seconds: 4),
            () => MyDeepLink(),
          ),
        ),
      ];
}

Important Information About [Async Binds]

  • Through the [Injector.] shortcut, you can wait for your asynchronous Binds to be ready before starting any action. This is usually used during the transition from the SplashPage to load asynchronous dependencies.

Example:

class InitializeController with FlutterGetItMixin {
  InitializeController();
  @override
  void dispose() {}

  @override
  void onInit() async {
    await Injector.allReady();
    // Do something
  }
}

Important Information About [Bind.factory] and [Bind.factoryAsync]

  • Each time you request an instance from FlutterGetIt, the factory will return a new instance of the requested object. However, you can define a [factoryTag] when instantiating the object. With this, FlutterGetIt will assign this tag to the object, making it unique in the tree. This way, when you request the object using the same tag, FlutterGetIt will return the already created instance, avoiding duplications and allowing the object to be called in other locations with the precision of the tag. You can also remove a Bind based on its [factoryTag].

Example of creation:

final fGetIt = context.get<FormItemController>(factoryTag: 'UniqueKeyString');

// Now this object is assigned to this tag, and in case of hotReload or request in another location, FlutterGetIt can identify it and prevent a new Object from being generated in the factory.

// Example in another controller.
final factoryCreatedInHomePage = context.get<FormItemController>(factoryTag: 'UniqueKeyString');

Example of removal:

Injector.unRegisterFactory<FormItemController>(UniqueKeyString);

// Here we will remove all objects of type T
Injector.unRegisterAllFactories<FormItemController>();
UI and Widgets
  • FlutterGetIt provides a set of tools to assist in using components and rules in the UI.

FlutterGetItWidget

Attribute Description
name The id is used for identifying the element internally and in the extension, for example, "/HomeWidget" or "WidgetCounter".
binds Binds that will be instantiated and removed in the same lifecycle as the [widget or page] that uses them.
onDispose Here you can execute an action before the Binds are closed and removed.
onInit Here you can execute an action right after the Binds are initiated.
builder Widget construction.

Example:

 FlutterGetItWidget(
      name: id,
      binds: [
        Bind.factory(
          (i) => FormItemController(
            name: 'FormItemController',
          ),
        ),
      ],
      onDispose: () {
        Injector.unRegisterFactory<FormItemController>(id);
      },
      builder: (context) {
        final fGetIt = context.get<FormItemController>(factoryTag: id);
        return Column(
          children: [
            Text(fGetIt.name),
            const SizedBox(height: 10),
            TextField(
              decoration: InputDecoration(
                labelText: fGetIt.name,
                border: const OutlineInputBorder(),
              ),
            ),
          ],
        );
      },
    );

FlutterGetItView

  • [FlutterGetItView] is a shortcut that extends [StatelessWidget], allowing you to reduce the amount of code in the widget.
  • Using it will provide a variable called [fGetit] that will take the value passed in [FlutterGetItView].

Example:

class ActiveAccountPage extends FlutterGetItView<ActiveAccountController> {
  const ActiveAccountPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(fGetIt.name),
      ),
      body: ...,
    );
  }
}

Adding Lifecycle to Binds

FlutterGetItMixin - Object Lifecycle
  • FlutterGetIt offers the [FlutterGetItMixin] mixin, which can be applied to your class, allowing the object to have a complete lifecycle, with initialization and finalization methods.
Attribute Description
onDispose Called when the object is removed.
onInit Called the first time the object is instantiated.

Example:

class ActiveAccountController with FlutterGetItMixin {
  final String name;

  ActiveAccountController({required this.name});
  @override
  void onDispose() {}

  @override
  void onInit() {}
}

FlutterGetIt.navigator - Navigator 2.0

  • FlutterGetIt supports Navigator 2.0, allowing you to instantiate modules and routes exclusively for the internal context. To do this, simply wrap the "Navigator" with [FlutterGetIt.navigator].
Attribute Description
navigatorName Navigator name for identification in the tree and extension.
bindings Same rules used for main bindings, but must extend [NavigatorBindings] instead of [ApplicationBindings].
pages Assignment of routes as in the "main".
modules Assignment of modules as in the "main".
builder Returns the context and routes as in the "main".

Example:

 Scaffold(
      body: FlutterGetIt.navigator(
        navigatorName: 'NAVbarProducts',
        bindings: MyNavigatorBindings(),
        modulesRouter: [
          FlutterGetItModuleRouter(
            name: '/Random',
            bindings: [
              Bind.lazySingleton<RandomController>(
                (i) => RandomController('Random by FlutterGetItPageRouter'),
              ),
            ],
          pages: [
              FlutterGetItPageRouter(
                name: '/Page',
                page: (context) => const RandomPage(),
                ),
              ]
          ),
        ],
        modules: [
          HomeModule(),
          DetailModule(),
          AuthModule(),
        ],
        builder: (context, routes) => Navigator(
          key: internalNav,
          initialRoute: '/Home/Page',
          observers: const [],
          onGenerateRoute: (settings) {
            return PageRouteBuilder(
              settings: settings,
              pageBuilder: (context, animation, secondaryAnimation) =>
                  routes[settings.name]?.call(context) ?? const Placeholder(),
            );
          },
        ),
      ),
      bottomNavigationBar: BottomNavigationBar...
      ...
      ...

Route Outlet

What is a RouteOutlet

The "Router Outlet" is a marker where the router inserts the component corresponding to the active route. This feature is extremely important in all applications as it allows you to add a component and load pages based on routes.

How to Use It

To use it, simply add the FlutterGetItRouteOutlet widget to the page where you want to have internal navigation. In it, you should configure the initial route (initialRoute) and the navigation key. With this, all navigation registered in the Material App will be loaded within the Router Outlet.

Here is a complete example with BottomNavBar:

 Scaffold(
      body: FlutterGetItRouteOutlet(
        initialRoute: '/Auth/Login',
        navKey: internalNav,
        transitionsBuilder: (context, animation, secondaryAnimation, child) => ScaleTransition(
          scale: Tween<double>(begin: 0.0, end: 1.0).animate(animation),
          child: child,
        ),
      ),
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _currentIndex,
        onTap: (value) {
          if (_currentIndex != value) {
            switch (value) {
              case 0:
                internalNav.currentState
                    ?.pushNamedAndRemoveUntil('/Auth/Login', (_) => false);
              case 1:
                internalNav.currentState?.pushNamedAndRemoveUntil(
                    '/Auth/Register/Page', (_) => false);
              case 2:
                internalNav.currentState
                    ?.pushNamedAndRemoveUntil('/RootNavBar/Root', (_) => false);
              case 3:
                internalNav.currentState
                    ?.pushNamedAndRemoveUntil('/Landing/Initialize', (_) => false);
            }
            setState(() {
              _currentIndex = value;
            });
          }
        },
        items: const [
          BottomNavigationBarItem(
            icon: Icon(
              Icons.home,
              color: Colors.blueAccent,
            ),
            label: 'Login',
          ),
          BottomNavigationBarItem(
            icon: Icon(
              Icons.production_quantity_limits,
              color: Colors.blueAccent,
            ),
            label: 'Register',
          ),
          BottomNavigationBarItem(
            icon: Icon(
              Icons.home,
              color: Colors.blueAccent,
            ),
            label: 'Custom NavBar',
          ),
           BottomNavigationBarItem(
            icon: Icon(
              Icons.home,
              color: Colors.blueAccent,
            ),
            label: 'Presentation',
          ),
        ],
      ),
    );

Customizing the Transition Animation

You can also customize the transition animation by adding the transitionsBuilder attribute.

transitionsBuilder: (context, animation, secondaryAnimation, child) => ScaleTransition(
  scale: Tween<double>(begin: 0.0, end: 1.0).animate(animation),
  child: child,
),

Example Project

Example Project

카테고리

의존성

의존성 목록 1 개

소스 저장소

이 패키지를 사용하는 프로젝트

아직 데이터가 없습니다.