본문 바로가기

안드로이드

[Android] Dagger 관련 스택 오버 플로우 질의 번역 - subcomponent with contibutor

개요

해당 게시글은 스택 오버 플로우의 게시글을 번역한 게시글입니다.

 

질문 내용

현재 @ContributesAndroidInjector를 통해 fragment를 주입하는데 문제가 있다.

 

모듈 내에서 계층 구조를 만드려고 하는 상황이며, 현재 존재하는 것은

  • Core
  • App
  • Feature

현재 AppComponent는 CoreComponent에 의존성을 가집니다.

@Singleton
@Component(modules = [CoreModule::class])
interface CoreComponent {

    fun getApp(): Application

    @Component.Factory
    interface Factory {
        fun create(@BindsInstance app: Application): CoreComponent
    }
}
@AppScope
@Component(
    modules = [
        AndroidInjectionModule::class,
        ActivityContributor::class,
        AppModule::class],
    dependencies = [CoreComponent::class]
)
interface AppComponent : AndroidInjector<App> {

    @Component.Factory
    interface Factory {
        fun create(component: CoreComponent): AppComponent
    }
}

위의 내용은 매우 간단하다. AppComponent에는 MainActivity를 @ContributesAndroidInjector 처리한 내용만 있는 ActivityContributor가 있다.

 

지금 문제는 캡슐화된 feature subcomponent를 추가하려하는 상황이다. 만약 공통적인 종속성과 일부 자체적인 종속성을 가진 2개의 프래그먼트가 feature에 있다고 가정한다.

 

내가 원하는 구현 사항은  FeatureModule과 FeatureContributor가 있는 FeatureSubcomponent를 만드는 것이다.

@FeatureScope
@Subcomponent(
    modules = [FeatureContributor::class,
        FeatureModule::class
    ]
)
abstract class FeatureSubcomponent {

    @Subcomponent.Factory
    interface Factory {
        fun create(): FeatureSubcomponent
    }
}

 FeatureModule은 두 프래그먼트의 공통적인 종속성을 가지고, FeatureContributor는 FragmentOne과 FragmentTwo를 각각 자체 모듈과 함께 contrbuting한다.

 

@Module
abstract class FeatureContributor {

    @ContributesAndroidInjector(modules = [FeatureOneModule::class])
    abstract fun featureOneFragment(): FeatureOneFragment

    @ContributesAndroidInjector(modules = [FeatureTwoModule::class])
    abstract fun featureTwoFragment(): FeatureTwoFragment
}

 

그리고 당연히 FeatureSubcomponent를 AppModule의 subcomponent로 추가했다.

AppModule:

@Module(subcomponents = [FeatureSubcomponent::class])

위에 스크롤해보면 AppModule이 AppComponent에 속해있는 것을 확인할 수 있을 것이다.

 

문제는 이걸 컴파일하고 실행시켜보면 No Injector factory bound for 에러가 발생하며 크래쉬가 발생한다.

 

대략적으로 내 구조는 아래와 같다:

  • CoreComponent
  • AppComponent
    • FeatureComponent
      • FeatureOneComponent
      • FeatureTwoComponent

혹시 왜 이러는지 혹은 어떻게 대체해야하는지 아는 사람이 있나? 혹시 아니면 내가 놓친 부분이라도?

 

아래는 내가 만드려고 하는 계층을 쉽게 도식화한 다이어그램이다.

 

 

 

채택된 답변

대거 안드로이드는 현재 스코프에서 가장 가까운 인젝터를 찾아 의존성 주입을 수행한다. 프래그먼트이 경우, 액티비티를 포함하고, 액티비티는 애플리케이션 객체를 포함한다.

 

만약 당신이 AndroidInject.inject(this)를 프래그먼트에서 호출하면 계층을 따라 위로 올라가면서 인젝터를 찾고 프래그먼트를 주입할 것이다.

 

DaggerAppCompatActivity나 HasFragmentInjector를 상속하거나 구현했나?

 

내가 파악한 다른 점은 왜 @ContributesAndroidInjector로 이미 subcomponent를 내부적으로 생성했는데 다시 subcomponent를 생성했는지 궁금하다.

 

@ContributesAndroidInjector.module은 subcomponent를 생성하라는 방법 중 하나이다. 그래서 액티비티와 FeatureFragment 사이의 관계는 @ContributesAndroidInjector가 생성할 subcomponent에서 설정되어야 한다.

 

AppCompat의 subcomponent로 FeatureComponent를 지정했기 때문에 현재 당신의 계층구조는 이와 같다.

App -> FeatureSubComponent -> [A, B] (generated)
      \
       \---> MainActivitySubcomponent (generated by contributesAndroidInjector).

실제로 당신이 원하는건 아래이다.

App -> MainActivitySubComponent (generated) -> [Feature A , Feature B] (generated)

 

아래와 같이 작성해라.

@ContributesAndroidInjector(modules = [FeatureContributor::class])
abstact fun mainActivity() : MainActivity

 

FeatureContributor는 @ContributesAndroidInjector를 내부적으로 가질 수 있다. 대거 컴파일러가 FeatureContributor가 @ContributesAndroidInjector를 발견하면 액티비티의 subcomponent로 해당 subcomponent를 생성할 것이다.

 

이게 기본적으로 Activity -> Fragment의 계층이다.