? android hilt적용하려고 하니까, 무슨 모듈에 등록을해야한대. repositoryModule에 등록하기
@Binds
abstract fun bindSearchHomeRepository(repo: SearchHomeRepositoryImpl): SearchHomeRepository
Hilt 를 Android 프로젝트에 적용할 때 @Binds를 사용하여 repository를 모듈에 등록한다.
1. Repository Module이란?
interface SearchHomeRepository {
API 호출이 필요한 메소드들 추가
}
class SearchHomeRepositoryImpl @Inject constructor(@NetworkModule.GWNetworkAPI private val apiService: Lazy<RetrofitService>) : SearchHomeRepository {
override로 해당 메소드들 구현
}
@Module
@InstallIn(SingletonComponent::class)
abstract class RepositoryModule {
@Binds
abstract fun bindSearchHomeRepository(repo: SearchHomeRepositoryImpl): SearchHomeRepository
}
@Module
@InstallIn(SingletonComponent::class)
abstract class RepositoryModule {
@Binds
abstract fun bindSearchHomeRepository(repo: SearchHomeRepositoryImpl): SearchHomeRepository
}
-abstract fun : @Binds 는 항상 abstract 함수에 사용된다. 실제 구현은 Hilt 가 컴파일 타임에 생성.
bindSearchHomeRepository : 함수 이름. 관례적으로 bind접두사를 붙이지만 기능적으로 이름이 중요한건 아님.
repo : SearchHomeRepositoryImpl : 이 매개변수는 Hilt가 제공할 구현체입니다. Hilt는 이 타입의 인스턴스를 어떻게 생성할지 알아야한다(보통 생성자 주입을 통해)
SearchHomeRepository : 반환 타입은 바인딩하려는 인터페이스!! 이것은 의존성 주입 시 실제로 요청하는 타입.
class SearchViewModel @Inject constructor(
private val searchHomeRepository: SearchHomeRepository
) {
// SearchHomeRepository 인터페이스를 사용하지만,
// 실제로는 SearchHomeRepositoryImpl이 주입됩니다
}
-> 이렇게 하면 구체적인 구현에 의존하지 않고, 인터페이스에만 의존하게 되어 유연하고 테스트 하기 쉬운 코드를 작성할 수 있음!
프래그먼트에 @AndroidEntryPoint 를 추가
-> @AndroidEntryPoint 어노테이션은 Hilt를 Android 컴포넌트에 적용하기 위한 핵심 요소.
이 어노테이션을 Fragment에 추가하면 해당 Fragment에서 Hilt의 의존성 주입 기능을 사용할 수 있게 된다.
@AndroidEntryPoint의 역할과 기능
1. Hilt 의존성 주입 활성화: 이 어노테이션이 적용된 Fragment는 Hilt의 의존성 주입 시스템에 참여할 수 있게 된다.
2. 코드 생성 트리거: 컴파일 시점에 Hilt는 이 어노테이션을 보고 필요한 의존성 주입 코드를 자동으로 생성.
3. 부모 컴포넌트 연결: Fragment의 부모인 Activity도 @AndroidEntryPoint로 표시되어 있어야 하며, Hilt는 이러한 계층 구조를 인식하여 적절한 의존성 그래프를 구성하게됨.
@AndroidEntryPoint
class SearchHomeFragment : Fragment() {
// @Inject 어노테이션으로 의존성 주입
@Inject
lateinit var viewModelFactory: ViewModelProvider.Factory
// 또는 by viewModels()를 사용해 ViewModel 주입받기
private val viewModel: SearchViewModel by viewModels()
// Fragment 생명주기 메서드들...
override fun onCreateView(...) { ... }
}
주요 특징
중요 고려사항
뷰모델 선언 수정
: @AndroidEntryPoint와 Hilt를 적용한 후에는 기존의 ViewModel 초기화 방식을 더 간단하게 변경할 수 있다. 기존에 사용하시던 코드는:
private val vm: SearchViewModel by lazy { ViewModelProvider(this)[SearchViewModel::class.java] }
이 코드는 전통적인 방식으로 ViewModel을 초기화하는 방법.. Fragment가 생성될 때 lazy 초기화를 통해 ViewModelProvider를 사용하여 SearchViewModel의 인스턴스를 가져온다.
Hilt와 @AndroidEntryPoint를 적용한 후에는 이 코드를 다음과 같이 더 간결하게 변경할 수 있다
private val vm: SearchViewModel by viewModels()
by viewModels()와 기존의 ViewModelProvider 방식은 모두 ViewModel을 초기화하는 방법이지만 차이점이 있음.
1. by viewModels()
// 예: 부모 Fragment와 ViewModel 공유
private val sharedVM: SharedViewModel by viewModels({ requireParentFragment() })
// 예: 커스텀 팩토리 제공
private val vm: SearchViewModel by viewModels { customFactory }
4. SavedStateHandle 지원
기존 방식: SavedStateHandle을 사용하려면 AbstractSavedStateViewModelFactory 등의 복잡한 설정이 필요...
by viewModels(): SavedStateHandle이 필요한 ViewModel에 자동으로 주입됨!
5. 테스트 용이성: 테스트 시 가짜(fake) 또는 모의(mock) 의존성을 쉽게 교체할 수 있습니다.
6. 스코프 관리: ViewModel의 생명주기가 Fragment 또는 Activity의 생명주기에 맞게 자동으로 관리됩니다.
-지연 초기화: 프로퍼티에 처음 접근할 때 ViewModel 인스턴스가 초기화됨.
-생명주기 인식: Fragment나 Activity의 생명주기에 맞춰 ViewModel 인스턴스를 관리한다.
-구성 변경 유지: 화면 회전 등의 구성 변경 시에도 ViewModel 인스턴스를 유지!!!
-ViewModelStoreOwner 활용: 내부적으로 Fragment나 Activity의 ViewModelStore를 사용하여 ViewModel 인스턴스를 저장.
이렇게 변경하려면 SearchViewModel 클래스도 다음과 같이 수정해야 됨:
@HiltViewModel
class SearchViewModel @Inject constructor(
private val searchHomeRepository: SearchHomeRepository
// 기타 필요한 의존성들...
) : ViewModel() {
// ViewModel 코드
}
@HiltViewModel 어노테이션은 Hilt에서 ViewModel을 위해 특별히 제공하는 어노테이션이다. 이 어노테이션을 사용함으로써 Hilt가 Android의 ViewModel 아키텍처 컴포넌트와 통합되어 작동하도록해줌!
@HiltViewModel 어노테이션의 역할
1.ViewModel 의존성 주입 활성화: 이 어노테이션이 있는 ViewModel 클래스는 Hilt의 의존성 주입 시스템에 참여하게됨.
2.ViewModelComponent 생성: Hilt는 이 어노테이션이 붙은 ViewModel을 위한 특별한 컴포넌트를 생성하여 ViewModel 범위의 의존성을 관리한다.
3. SavedStateHandle 지원: 자동으로 SavedStateHandle을 주입할 수 있도록 지원.
4. by viewModels() 연결: @AndroidEntryPoint로 표시된 Fragment나 Activity에서 by viewModels()를 사용해 접근할 수 있게 됨.
위의 코드 분석
이 코드를 분석해보면:
사용 이점
1.생명주기 관리: ViewModel의 생명주기를 Android 아키텍처 컴포넌트와 일치시킨다.
2.스코프 관리: ViewModel 인스턴스는 해당 Fragment/Activity의 생명주기 동안 유지된다.
3.테스트 용이성: 테스트 환경에서 쉽게 가짜 의존성을 주입할 수 있다.
4.의존성 그래프 통합: Hilt의 전체 의존성 그래프에 ViewModel이 통합된다
@HiltViewModel 사용 시 중요 사항
1.SavedStateHandle 사용: 필요한 경우 다음과 같이 SavedStateHandle을 주입받을 수 있다:
@HiltViewModel
class SearchViewModel @Inject constructor(
private val searchHomeRepository: SearchHomeRepository,
private val savedStateHandle: SavedStateHandle
) : ViewModel() { ... }
2.ViewModelComponent 스코프: @HiltViewModel이 적용된 ViewModel은 ViewModelComponent에 설치된 모듈의 의존성에 접근할 수 있다.
3.Fragment/Activity 연결: 이 ViewModel을 사용하는 Fragment나 Activity는 반드시 @AndroidEntryPoint로 표시되어 있어야 한다.
요약하자면, @HiltViewModel은 Android의 ViewModel 시스템과 Hilt의 의존성 주입 시스템을 매끄럽게 통합하여, 깔끔하고 테스트 가능한 아키텍처를 구현할 수 있게 해주는 중요한 어노테이션!