Daniel Weidensdörfer
12/23/2024, 2:20 PMeygraber
12/24/2024, 2:54 AM@Component
a lot because the docs showed things like RealNetworkComponent
.
However, structuring your component hierarchy like that means that other parent components of AppComponent
wouldn't be able to inject anything from RealNetworkComponent
.
My solution to that (and answer to @Daniel Weidensdörfer) has been to use a hierarchy of AppComponent
, ActivityComponent
and ScreenComponent
, with a corresponding scope for each one (obviously an Android solution, but the concept extends to any other system).
Instead of having a NetworkComponent
I declare a NetworkModule
interface and have the appropriate component implement it (or more recently just use kotlin-inject-anvil and ContributesTo
).Daniel Weidensdörfer
12/24/2024, 1:30 PMdomain
, data
, feature1
, feature2
, app
modules. With obvious dependencies data
<- `domain`<- features
<- app
.
Currently I have a component for each of the gradle modules. Since there is no "Master" component that contains everything, each feature gets its references from its own component FeatureXComponent which in turn reference the DomainComponent (if needed).
The DomainComponent cannot be a "Module" interface as two different trees would be generated for each child feature.
So with this architecture, I'm creating a new scope XXXSingleton for each component. While I'm asking myself why there is no global Singleton annotation provided by the framework.Marcelo Gobetti
05/02/2025, 9:51 PM@Component abstract class
path.
there are a few drawbacks with using interfaces, especially when `internal`s are involved (to Daniel's point on modularization), but after some time trying your idea out:
a hierarchy ofI finally got to a place that feels familiar with other projects, and while boilerplate exists in different forms, it's smaller and easier to handle than the other options, it seems. ------ @Daniel Weidensdörfer thank you for the original post, I had the same question and struggle, and was going the same route of components being 1:1 with gradle modules. I think what Eliezer is suggesting is we wouldn't have `@Component`s per module, but interfaces, and then only a few "master" components that implement them: those 3 he pointed out (where I understand,AppComponent
andActivityComponent
ScreenComponent
ScreenComponent
means N of those for N screens, i.e. HomeScreenComponent
, SettingsScreenComponent
etc.)
by having fewer components, you automatically have fewer scopes, as all the interfaces implemented by 1 component can use that 1 scope
@ApplicationScope
@Component
abstract class ApplicationComponent(
@get:Provides val context: Context
) : DataComponent, NetworkComponent
...
@ActivityScope
@Component
abstract class ActivityComponent(
@Component val applicationComponent: ApplicationComponent
) : InAppReviewComponent, SplashScreenComponent
...
@HomeScreenScope
@Component
abstract class HomeScreenComponent(
@Component val activityComponent: ActivityComponent
) : HomeStuffComponent
this is one of the repos that helped shape my ideas. While learning, I like to start simple, so it's been helpful to me that it doesn't use Anvil, which would be another thing for me to learn from zeroDaniel Weidensdörfer
05/06/2025, 8:10 AMDomainModule
as interface and ScreenAComponent
and ScreenBComponent
that use that interface.
If you want to mark a use case binding in DomainModule
as singleton, would you mark it with ScreenAScope
and ScreenBScope
? The thing is that if the module as interface is used by 2 components, it will be 2 different dependency trees and the usecase which is supposed to be a singleton in the whole application is effectevly created once for each component.
I'm currently doing very well with having a component for each module with its own scope. Also because I created some scoping in form of having one component for a user for example (To clean up coroutines when user logs out).eygraber
05/06/2025, 11:19 AMScreenScope
which is the parent of each screen's scope, and maintains separate singletons for each screen. It exists for exactly that purpose; to provide a screen level scope outside of the screen module.Daniel Weidensdörfer
05/06/2025, 2:41 PMeygraber
05/06/2025, 2:43 PMAppScope
Marcelo Gobetti
05/06/2025, 3:48 PMDomainModule
can use ScreenScope
, and the two different screen components that implement that interface use that scope too. Right?eygraber
05/06/2025, 3:50 PM