-
Notifications
You must be signed in to change notification settings - Fork 18
Dependency auto scoping
This article explains how to create hierarchical scopes and how Magnet creates and binds instances into those scopes.
- Create the root scope for your objects inside of you
Application
. Created scope has same lifespan as your application.
val appScope = Magnet.createRootScope()
- Inside of your
Activity
create another scope with a shorter lifespan, corresponding to the lifespan of your activity. Lets create and initialize it with an instance ofResources
which will reside inside this scope.
val activityScope = App.appScope.createSubscope {
bind(resources)
}
Created scope holds a reference to its parent scope which is appScope
.
- Lets create a third empty scope with a
Fragment
lifespan.
val fragmentScope = activityScope.createSubscope()
fragmentScope
holds reference to activityScope
. Any object created in fragmentScope
can depend on the objects registered in the same scope or in any parent scope up to the root scope, meaning in either activityScope
or appScope
.
Our scope setup look like this
appScope ()
^
|
activityScope (resources)
^
|
fragmentScope ()
appScope
and fragmentScope
are empty and activityScope
has a single Resources
object in it.
- Let's imagine we need to create following instances with dependencies between them.
FragmentPresenter -> ItemRepository -> ItemDataSource -> Resources
First we need to declare them using @Instance
annotation.
@Instance(type = FragmentPresenter::class, scoping = Scoping.DIRECT)
class FragmentPresenter(
private val itemRepository: ItemRepository
)
@Instance(type = ItemRepository::class)
class ItemRepository(
private val dataSource: ItemsDataSource
)
@Instance(type = ItemDataSource::class)
class ItemDataSource(
private val resources: Resources
)
Magnet parses constructors of annotated classes, generates class factories and handles dependencies between them.
- Now we can ask Magnet to provide instance of
FragmentPresenter
class fromfragmentScope
like following.
val fragmentPresenter = fragmentScope.getSingle<FragmentPresenter>()
Magnet will resolve dependencies, create objects and bind them into our scopes automatically as following.
appScope ()
^
|
activityScope (itemRepository, itemDataSource, resources)
^
|
fragmentScope (fragmentPresenter)
Here is the explanation of how Magnet managed auto-scoping of objects.
a) fragmentPresenter
was bound to fragmentScope
because of scoping = Scoping.DIRECT
directive forcing Magnet to register objects in the same scope, in which they were requested. Magnet did it because we called getSingle()
at fragmentScope
.
b) itemDataSource
was bound to activityScope
because this is the top most scope where its dependency (resources
) is available. This is controlled by scoping = Scoping.TOPMOST
directive, which is default scoping value. If resources
would reside inside appScope
, then Magnet would put itemDataSource
into appScope
too.
c) itemRepository
was bound to activityScope
because its dependency itemDataSource
resides inside activityScope
. Same as the case (b).
Auto-scoping and dependency inversion are some of the concepts differentiating Magnet from the other injection frameworks out there. Those concepts are new and they have to be validated by using them in smaller projects first. Feel free to check Magnet and share your opinion and ideas.