T
T
Tsuzukeru2021-05-11 16:12:25
Android
Tsuzukeru, 2021-05-11 16:12:25

How to DI in an Activity using dependencies?

There is an application consisting of the class App and Activity. Each class has a module that provides a string:

@Module
class AppModule {

    @Named("app string")
    @Provides
    fun provideSimpleString(): String {
        return "Dagger app string"
    }
}


@Module
class ActivityModule {

    @Named("activity string")
    @Provides
    fun provideSimpleString(): String {
        return "Dagger activity string"
    }
}


There are also two components, respectively:

@Singleton
@Component(modules = [AppModule::class])
interface AppComponent {

    @Component.Factory
    interface Factory {
        fun create(): AppComponent
    }
    
    fun inject(app:App)
}


@ActivityScope
@Component(dependencies = [AppComponent::class], modules = [ActivityModule::class])
interface ActivityComponent {

    @Component.Factory
    interface Factory {
        fun create(): ActivityComponent
    }

    fun inject(mainActivity: MainActivity)
}


Activity and App classes
class App : Application() {
    lateinit var appComponent: AppComponent

    override fun onCreate() {
        super.onCreate()
        appComponent = DaggerAppComponent.factory().create()
        appComponent.inject(this)
    }
}


class MainActivity : AppCompatActivity() {
    @Inject
    @Named("app string") lateinit var appString: String
    @Inject
    @Named("activity string")lateinit var activityString: String

    lateinit var activityComponent: ActivityComponent

    override fun onCreate(savedInstanceState: Bundle?) {
        activityComponent = DaggerActivityComponent.factory().create()
        activityComponent.inject(this)
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        Log.i(TAG, "onCreate: $appString")
        Log.i(TAG, "onCreate: $activityString")
    }

    companion object {
        private const val TAG = "MainActivity"
    }
}


Build error.
error: @Component.Factory method is missing parameters for required modules or components: [com.app.di.di.AppComponent]

Rewrite activityComponent() to the following:
@ActivityScope
@Component(dependencies = [AppComponent::class], modules = [ActivityModule::class])
interface ActivityComponent {

    @Component.Factory
    interface Factory {
        fun create(appComponent: AppComponent): ActivityComponent
    }

    fun inject(mainActivity: MainActivity)
}


Rewriting activity:
class MainActivity : AppCompatActivity() {
    @Inject
    @Named("app string") lateinit var appString: String
    @Inject
    @Named("activity string")lateinit var activityString: String

    lateinit var activityComponent: ActivityComponent
    lateinit var appComponent:AppComponent

    override fun onCreate(savedInstanceState: Bundle?) {
        appComponent = (application as App).appComponent
        activityComponent = DaggerActivityComponent.factory().create(appComponent)
        activityComponent.inject(this)
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        Log.i(TAG, "onCreate: $appString")
        Log.i(TAG, "onCreate: $activityString")
    }

    companion object {
        private const val TAG = "MainActivity"
    }
}


Now another build error:

/home/x/GIT/DI/app/build/tmp/kapt3/stubs/debug/com/app/di/ui/activity/ActivityComponent.java:8: error: [Dagger/MissingBinding] javax .inject.Named("app string") java.lang.String cannot be provided without an @Provides-annotated method.

Answer the question

In order to leave comments, you need to log in

1 answer(s)
D
Denis Zagaevsky, 2021-05-11
@Tsuzukeru

For this to work, the dependency bean must have explicit provision methods (getters) for everything that needs to fall into the other bean's graph. In your case, you need to add a method to the AppComponent

@Named("app string")
 fun appString(): String

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question