일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- Rxjava Observable
- rxjava disposable
- 안드로이드 유닛테스트란
- 안드로이드 레트로핏 사용법
- 멤버변수
- 자바 다형성
- 2022 플러터 안드로이드 스튜디오
- 서비스 쓰레드 차이
- 안드로이드 유닛 테스트
- 클래스
- ANR이란
- android ar 개발
- 큐 자바 코드
- 서비스 vs 쓰레드
- rxjava hot observable
- 안드로이드 레트로핏 crud
- 객체
- 안드로이드 라이선스
- ar vr 차이
- jvm이란
- 안드로이드 os 구조
- 플러터 설치 2022
- rxjava cold observable
- 스택 자바 코드
- 안드로이드 유닛 테스트 예시
- android retrofit login
- 스택 큐 차이
- 2022 플러터 설치
- jvm 작동 원리
- 안드로이드 라이선스 종류
- Today
- Total
나만을 위한 블로그
[Android] hilt 사용 시 동일 객체의 중복 바인딩을 허용하는 방법 본문
같은 타입인 객체의 중복 바인딩을 유지하면서 사용해야 할 경우가 있다. 예를 들어 base url이 서로 다른 레트로핏 객체를 생성하고 싶을 수 있다.
그러나 hilt는 같은 타입의 객체를 바인딩하려고 하면 DuplicateBindings 태그가 포함된 에러가 발생한다.
이 때 사용할 수 있는 hilt 어노테이션이 2가지 있다.
- Qualifier
- Named
각 어노테이션의 사용 방법을 간단하게 확인한다. 프로젝트에 hilt를 사용하도록 설정하는 건 생략한다.
먼저 Qualifier 어노테이션을 쓰기 전 아래 클래스들을 미리 작성해둔다.
import javax.inject.Inject
class Bar @Inject constructor() {}
class Foo constructor(val name: String) {}
import javax.inject.Qualifier
@Qualifier
annotation class MyQualifier
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
@Module
@InstallIn(SingletonComponent::class)
object FooModule {
@MyQualifier
@Provides
fun provideFirstFoo(): Foo {
return Foo(name = "first foo")
}
@Provides
fun provideSecondFoo(): Foo {
return Foo(name = "second foo")
}
}
참고로 annotation class에 @Qualifier 말고도 @Retention(AnnotationRetention.BINARY)를 쓰는 경우가 있다.
이걸 쓰는 이유는 @Qualifier의 기본 Retention 정책은 RUNTIME이기 때문에, 다른 정책을 사용하려면 이 어노테이션을 명시해야 한다.
참고로 BINARY, RUNTIME 값의 효과는 아래와 같다.
- RUNTIME : 런타임에도 어노테이션 정보를 유지. Qualifier 사용 시 반드시 명시할 필요는 X
- BINARY : 컴파일 타임까지 어노테이션 정보를 유지하지만 런타임에는 유지하지 않음
성능 최적화와 관련된 속성이기 때문에 관심이 있다면 따로 찾아보자. 여기선 자세히 확인하지 않고 넘어간다.
이후 액티비티에서 생성한 의존성을 사용한다.
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
private val TAG = this::class.simpleName
@Inject
lateinit var foo: Foo
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
@Inject
fun injectFoo(foo: Foo) {
Log.e(TAG, "injectFoo() - foo name : ${foo.name}")
this.foo = foo
}
}
이러고 실행하면 어떤 provide 함수가 호출될까?
실행해 보면 second foo가 호출된다. 의도했던 건 provideFirstFoo()를 호출하는 것이었는데 provideSecondFoo()가 호출된 것이다.
메서드 주입 방식으로 Foo 인스턴스를 주입받았는데, 이 때는 매개변수에도 내가 만든 커스텀 Qualifier를 써줘야 의도한 대로 provideFirstFoo()가 호출될 수 있다.
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
private val TAG = this::class.simpleName
@Inject
lateinit var foo: Foo
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
@Inject
fun injectFoo(@CustomQualifier foo: Foo) { // @CustomQualifier 추가
Log.e(TAG, "injectFoo() - foo name : ${foo.name}")
this.foo = foo
}
}
추가로 CustomQualifier에 간단한 값 지정을 할 수 있다.
User 클래스를 새로 만들고 이 클래스를 제공하는 모듈, 어노테이션 클래스도 새로 만든다.
@Qualifier
annotation class UserQualifier(
val age: Int,
val height: Double,
)
class User(val name: String)
@Module
@InstallIn(SingletonComponent::class)
object UserModule {
@Provides
@UserQualifier(30, 180.0)
fun provideA(): User {
return User("A")
}
@Provides
@UserQualifier(20, 160.0)
fun provideB(): User {
return User("B")
}
}
UserQualifier 클래스에 지정한 타입대로 값을 입력했다. 이후 액티비티에서 사용할 때도 여기서 설정한 값과 동일한 값을 넣어야 한다.
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
private val TAG = this::class.simpleName
@UserQualifier(30, 180.0)
@Inject
lateinit var a: User
@UserQualifier(20, 160.0)
@Inject
lateinit var b: User
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Log.e(TAG, "user a : ${a.name}")
Log.e(TAG, "user b : ${b.name}")
}
}
이것이 Qualifier의 대략적인 사용법이다. 다음은 @Named의 사용법을 확인해 본다.
마찬가지로 "first foo"가 로그로 출력되도록 한다.
@Module
@InstallIn(SingletonComponent::class)
object FooModule {
@Named("foo1")
@Provides
fun provideFirstFoo(): Foo {
return Foo(name = "first foo")
}
@Provides
fun provideSecondFoo(): Foo {
return Foo(name = "second foo")
}
}
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
private val TAG = this::class.simpleName
lateinit var foo: Foo
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
@Inject
fun injectFoo(
@Named("foo1") foo: Foo
) {
Log.e(TAG, "주입된 foo의 이름 : ${foo.name}")
this.foo = foo
}
}
사용법을 보면 알겠지만 @Named의 매개변수로 문자열 값을 전달받는다. 이 문자열 값이 키값이 되며 사용 시 동일하게 작성해야 정상적으로 쓸 수 있다.
'Android' 카테고리의 다른 글
[Android] MVI 패턴이란? (0) | 2024.07.03 |
---|---|
[Android] 안드로이드에서 hilt로 의존성 주입 구현하기 (0) | 2024.06.16 |
[Android] 뷰모델 초기화 방법 정리 (0) | 2024.05.21 |
[Android] 안드로이드 생태계 및 안드로이드 15 변경사항 (0) | 2024.05.20 |
[Android] stateIn이란? (0) | 2024.05.17 |