What else Dagger 2 injection provides?

Elye
Elye
Oct 16 · 3 min read

Many a times, we just use Dagger 2 to inject dependencies. But it could provides more than that. Take for example the below code

class Dependency @Inject constructor()

@Component
interface MainComponent {
fun inject(target: Target)
}

We think we could only get the Dependency object injected. But it also could provides the Provider<Dependency> and Lazy<Dependency>.

class Target {
@Inject
lateinit var dependency: Dependency
@Inject
lateinit var dependencyProvider: Provider<Dependency>
@Inject
lateinit var dependencyLazyProvider: Lazy<Dependency>

init {
DaggerMainComponent.builder().build().inject(this)
}
}

Both Provider and Lazy could be used to generate Dependency object.

The question is, are they the same copy generated, or different copies generated each time?

Generation of Provider/Lazy and its dependencies

Assume we instantiate 2 target objects code, where each has their own set of Dependency, Provider and Lazy

val target1 = Target()
val target2 = Target()

From the diagram above, we could see that each Target will generate it’s own Dependency and Lazy. However the Provider is the same one shared across the Target.

However, if we used Provider and Lazy to generate two Dependencys further, below diagram show if a new copy or existing copy generated.

From diagram above, we would find out that Provider always produce a new Dependency each time it is generate. However for Lazy, each of it will generate the same Dependency. Which means it will only generate one instant of it, and reuse the previous instance made.

For Provide the get() code is as below

@Override
public Dependency get() {
return provideInstance();
}

public static Dependency provideInstance() {
return new Dependency();
}

For Lazy, the get() is as below

@Override
public T get() {
Object result = instance;
if (result == UNINITIALIZED) {
synchronized (this) {
result = instance;
if (result == UNINITIALIZED) {
result = provider.get();
instance = reentrantCheck(instance, result);
/* Null out the reference to the provider.
* We are never going to need it again, so we
* can make it eligible for GC. */
provider = null;
}
}
}
return (T) result;
}

Singleton

What if we scope Dependency to Singleton as below?

@Singleton
class Dependency @Inject constructor()

@Singleton
@Component
interface MainComponent {
fun inject(target: Target)
}

Using the same code (as above) below

class Target {
@Inject
lateinit var dependency: Dependency
@Inject
lateinit var dependencyProvider: Provider<Dependency>
@Inject
lateinit var dependencyLazyProvider: Lazy<Dependency>

init {
DaggerMainComponent.builder().build().inject(this)
}
}

For Lazy and Provider, both will generate the same Lazy component. And all of them will generate the same Dependency, as shown below.

When should Provider/Lazy be used

In the event you need to generate an expensive dependencies, which might not be used, Provider or Lazy comes in handy if the dependencies is not “scope” variable. They could delay further the creation of the dependencies until it is needed.

As for Lazy and Provider, the different is, one will always generate the same copy, while the other will always generate a new copy each time.


Thanks for reading. You could check out my other topics here.

Follow me on medium, Twitter, Facebook or Reddit for little tips and learning on mobile development etc related topics. ~Elye~

Elye

Written by

Elye

Learning and Sharing Android and iOS Development

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade