Closed dimsuz closed 9 months ago
What you are doing ends up hiding NetworkComponent
from kotlin-inject so it can't find the NetworkScope
. The code it generates looks roughly like this, which you can see the issue more clearly:
class InjectActivityComponent(@Component val appComponent: AppComponent) : ActivityComponent {
override val viewModel: MainViewModel get() = MainViewModel(
// if appCompont isn't exposing networkComponent it doesn't know how to get items from it's scope
appComponent.networkComponent.get("CountHolder") { CounterHolder(networkComponent.respositoryCount()) }
)
}
So you need to expose your NetworkComponent
. You can also split it up with an interface/impl for some information hiding, but you'll need to make sure your dependencies are still reachable from it.
@NetworkScope
interface NetworkComponent {
// needed so value can still be provided through the interface
val repositoryCount: Int
}
@Component
abstract class NetworkComponentImpl {
@Provides
@NetworkScope
fun repositoryCount(): Int = 42
} : NetworkComponent
@Inject
@NetworkScope
class CountHolder(val repositoryCount: Int)
@AppScope
abstract class AppComponent(@Component val networkComponent: NetworkComponent)
@Component
abstract class AppComponentImpl(networkComponent: NetworkComponent) : AppComponent(networkComponent)
@ActivityScope
@Component
abstract class ActivityComponent(
@Component
val appComponent: AppComponent
) {
abstract val viewModel: MainViewModel
}
@ActivityScope
@Inject
class MainViewModel(val countHolder: CountHolder)
fun run() {
val activityComponent = ActivityComponent::class.create(
appComponent = AppComponentImpl::class.create(
networkComponent = NetworkComponentImpl::class.create()
)
)
println(activityComponent.viewModel.countHolder.repositoryCount)
}
(note: haven't actually tested above, lmk if something's wrong)
This was the part I was so close to and needed, but never grasped:
@AppScope
abstract class AppComponent(@Component val networkComponent: NetworkComponent)
I suspected that I need to mention networkComponent
in AppComponent
somehow, but my thinking was stuck on it being an interface
and I couldn't see how to do that.
Right! abstract class
!
Great, thank you very much, I'll test it tomorrow at work!
I'll close the issue as it is clear now that it's not a bug, and if I have further questions I'll ask them below :pray:
I will illustrate my problem with a sample. I tried to minimize it, but it's still quite verbose and has 3 components, sorry :)
The crux of the problem is that due to modularity concerns I want to hide a component impl inside a separate module and provide only a component interface, and if I do that dependency resolution breaks and kotlin-inject outputs an error. I'm not sure if this is a bug or I do something wrong.
If you insert this sample in IDE and compile, you'll get an error:
BUT if you go to the line marked "LINE A" and change
AppComponent
toAppComponentImpl
, then compilation is successful and everything works.But this defeats my goal of hiding
AppComponentImpl
in a module which no one depends on and having everyone depend on the module withinterface AppComponent
instead. Can I somehow achieve this?I can't mark
AppComponent
interface with@Component
(doesn't work), any other solutions maybe?