Get_it + Injectable 라이브러리 스터디

고랭지참치·2025년 4월 9일
0

Flutter

목록 보기
16/24

깃헙

https://github.com/MinwooRowan/get_it_study

사용한 패키지 버젼 정보

dependencies:
  flutter:
    sdk: flutter
  get_it: ^8.0.2
  injectable: ^2.5.0
  injectable_generator: ^2.6.2

dev_dependencies:
  flutter_test:
    sdk: flutter
  flutter_lints: ^4.0.0
  build_runner: ^2.4.13
  • Injectable은 Get_it을 더 유용하게 사용할 수 있도록 돕는 역할.
  • Like Dio & Retrofit

기본 사용법

GetIt Instance 글로벌하게 선언하기

final getIt = GetIt.instance;


void configureDependencies() =>  getIt.init();
  • GetIt은 싱글톤 서비스 로케이터로, 전역 변수로 할당해 사용하기 쉽고, 프로젝트 내 여러 장소에서 동일한 인스턴스에 접근할 수 있다.
🗒️

원문 :

As Dart supports global (or euphemistic ambient) variables I often assign my GetIt instance to a global variable to make access to it as easy as possible.

Although the approach with a global variable worked well, it has its limitations if you want to use GetIt across multiple packages. Therefore GetIt itself is a singleton and the default way to access an instance of GetIt is to call:

  • getIt.init()을 실행하는 함수 어노테이션에 @injectableInit을 넣은 후 buill runner를 돌리면 동일한 디렉토리 위치에 config파일이 자동 생성된다.
  • 이후 getIt에 등록한 클래스가 모두 config에 자동으로 추가된다.

클래스 생성

 // 사용할때마다 새로운 인스턴스 발행
class Viewmodel {}

 // 동일한 인스턴스 반환
class RepositoryImpl {}

 // 동일한 인스턴스 반환하나, 처음 사용할때 초기화
class RepositoryImpl {}

기본 사용

final HomeViewmodel viewmodel = getIt<HomeViewmodel>();
return HomeScreen(viewmodel: viewmodel);
  • getIt 인스턴스에 등록해둔 클래스들을 형태로 반환받을 수 있다.

파라미터

class HomeViewmodel extends ChangeNotifier {
  HomeViewmodel({
    required UserUsecase userUsecase,
     required this.id,
  }) : _userUsecase = userUsecase;
  final UserUsecase _userUsecase;
  final int id;
  • HomeViewmodel은 파라미터로 UserUsecasdid를 받는다고 할때, @factoryParam 어노테이션이 붙은 파라미터는 아래처럼 받을 수 있게 된다.
    • param은 최대 2개 까지만 받을 수 있다.
    • @factoryParam은 당연히 @singleton에는 사용할 수 없고, @injectable에서만 사용가능
    • @singleton에 일반 param추가시 getIt에 등록자체가 안된다.
final HomeViewmodel viewmodel = getIt<HomeViewmodel>(param1: 1);
  • @factoryParam이 붙지않은 파라미터들은 getIt에서 자동으로 등록된 의존성들에서 검색하여 추가한다. 따라서 해당 파람들은 모두 getIt에 등록을 해야하고 안해두면 빌드에러가 발생한다.
    gh.factoryParam<_i205.HomeViewmodel, int, dynamic>((
      id,
      _,
    ) =>
        _i205.HomeViewmodel(
          userUsecase: gh<_i291.UserUsecase>(),
          id: id,
        ));

초기화 순서 확인

class AppInit {
  static Future<void> init() async {
    WidgetsFlutterBinding.ensureInitialized();
    configureDependencies();
    logger.d('GET INITIALIZED');
  }
}

 // or @injectable
class HomeViewmodel extends ChangeNotifier {
  HomeViewmodel({
    required UserUsecase userUsecase,
  }) : _userUsecase = userUsecase {
    logger.d('HomeViewmodel INITIALIZED');
    getUserList = Command0(_getUserList);
  }
  • @injectable로 선언(@lazySingleton 동일)
    • “GET INITIALIZED” : 2024-12-11T10:12:48.25
      ”HomeViewmodel INITIALIZED” : 2024-12-11T10:12:48.42

      0.2초→ viewModel 사용될 때 초기화되는 것 확인

  • @singleton으로 선언했을때
    • ”HomeViewmodel INITIALIZED” : 2024-12-11T10:15:22.712723

      `“GET INITIALIZED”` **: 2024-12-11T10:15:22.721417**

      → Get It Initial될때 싱글톤 viewModel도 초기화되는 것 확인됨.

인터페이스 사용

  • Repository처럼 인터페이스를 구현하여 사용하는 클래스의 경우 어노테이션 파라미터에 as 를 사용하여 어떤 클래스의 구현체인지 명시할 수 있다.
    • config파일 확인해보면 인터페이스(UserRepository) 클래스로 등록된 것을 확인할 수 있다.
abstract class UserRepository {}
(as: UserRepository)
class UserRepositoryImpl implements UserRepository {}
gh.lazySingleton<_i291.UserUsecase>(
    () => _i291.UserUsecase(userRepository: gh<_i707.UserRepository>()));
  • 만약 한 인터페이스에 여러 구현체가 생긴다면 @Named 어노테이션을 활용하여 정의된 이름으로 구현체를 불러올 수 있다.
('LocalImpl')
(as: UserRepository)
class UserLocalRepositoryImpl implements UserRepository {}

('RemoteImpl')
(as: UserRepository)
class UserRepositoryImpl implements UserRepository {}


class UserUsecase {
  UserUsecase(('RemoteImpl') ARepository repository);
}
  • config에 각각의 이름으로 등록된 것을 확인할 수 있다.
gh.lazySingleton<_i707.UserRepository>(
  () => _i97.UserRepositoryImpl(userDatasource: gh<_i378.UserDatasource>()),
  instanceName: 'LocalImpl',
  dispose: (i) => i.dispose(),
);
gh.lazySingleton<_i707.UserRepository>(
  () =>
      _i97.UserRepositoryImpl2(userDatasource: gh<_i378.UserDatasource>()),
  instanceName: 'RemoteImpl',
  dispose: (i) => i.dispose(),
);

static 비동기 초기화 이후 사용 필요시

  • 클래스를 초기화하는 함수를 생성하고 @factoryMethod 어노테이션을 기입한다. 함수명은 마음대로.
  • Future<클래스명>로 비동기함수를 생성

class AsyncUserRepository {
  
  static Future<AsyncUserRepository> create() async {
    await Future.delayed(Duration(seconds: 2));
    return AsyncUserRepository();
  }
}
  • getIt config에서 factoryAsync로 불러오는 것을 확인할 수 있다.
gh.factoryAsync<_i578.AsyncUserRepository>(
    () => _i578.AsyncUserRepository.create());
  • 등록된 것을 확인후 getIt.getAsync로 호출하여 사용
final AsyncUserRepository repository = await getIt.getAsync<AsyncUserRepository>();

싱글톤 클래스 Dispose

  • @disposeMethod 어노테이션을 추가한 함수를 통해 싱글톤 폐기상황 로직을 처리할 수 있다.
 // or lazySingleton  
class DataSource {  
  
    
  void dispose(){  
  }  
}

Flavor 적용

  • Init 적용

void configureDependencies({String? environment}) =>
    getIt.init(environment: environment);
class AppInit {
  static Future<void> init() async {
    configureDependencies(environment: 'dev');
  }
}
  • 구현체에 적용
(
  as: UserRepository,
  env: ['dev', 'qa'],
)
class UserRepositoryImpl implements UserRepository {}

(
  as: UserRepository,
  env: ['prod'],
)
class UserRepositoryImpl2 implements UserRepository {}
  • env키에 넣은 키 값들이 자동으로 config에 등록된다.
**const String _prod = 'prod';
const String _dev = 'dev';
const String _qa = 'qa';**
gh.factory<_i707.UserRepository>(
  () =>
      _i97.UserRepositoryImpl2(userDatasource: gh<_i378.UserDatasource>()),
  instanceName: 'RemoteImpl',
  registerFor: {**_prod**},
);
gh.lazySingleton<_i291.UserUsecase>(() => _i291.UserUsecase(
    gh<_i707.UserRepository>(instanceName: 'RemoteImpl')));
gh.factory<_i707.UserRepository>(
  () => _i97.UserRepositoryImpl(userDatasource: gh<_i378.UserDatasource>()),
  instanceName: 'LocalImpl',
  registerFor: {
    **_dev,**
    **_qa,**
  },
);

Reference

https://pub.dev/packages/get_it

https://pub.dev/packages/injectable

https://orgeslayer.medium.com/flutter-di-get-it-injectable-624757613953

https://dev-yongsu.tistory.com/29

https://github.com/Milad-Akarie/injectable/blob/master/injectable/lib/src/injectable_annotations.dart

https://github.com/Milad-Akarie/injectable#disposing-of-singletons

profile
소프트웨어 엔지니어 / Flutter 개발자

0개의 댓글