Table of contents
Hey there! Remember when we chatted about those cool dagger injection methods in our last article? We also dived into the world of modules in Dagger2. Now, we're back at it, and this time, we're tackling a nifty challenge: passing values to objects on the fly. No more hardcoding, folks! Let's dive in and see how it's done.
The Challenge
Consider our older example, where we added a delay of a couple of seconds to the NetworkSetup
& NetworkSetupSecond
in the constructor. Let's assume that we'd like to pass it at runtime instead of hardcoding these values.
This would obviously change the code of our NetworkSetupSecond
to this:
public class NetworkSetupSecond implements NetworkLayer{
String TAG = this.getClass().getCanonicalName();
StorageLayer storageLayer;
public NetworkSetupSecond(StorageLayer storageLayer, int delay){
this.storageLayer = storageLayer;
try {
Log.e(TAG, "Initialising network second and delay is " + delay );
Thread.sleep(delay);
Log.e(TAG,"Network Second initialization done");
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.e(TAG, "Network Layer Second Created");
}
//....
}
Here, we are passing the delay as an argument in the constructor. Now we can easily pass this value to the NetworkSetupSecond
class from the NetworkModuleSecond
class where we had created this object, as shown below.
@Module
public class NetworkModuleSecond {
@Provides
NetworkLayer provideNetworkSetupSecond(StorageLayer storageLayer){
return new NetworkSetupSecond(storageLayer, 1000);
}
}
Let's build and run this program and check the logs.
Okay, so all good so far. We are able to pass an integer to our constructor from the module.
But Wait!
We actually want to pass this value at runtime, which basically means that we'd somehow like to pass this value from the MainActivity to our dagger graph after the app has been created.
And here lies the problem, how would we pass the delay
from our activity to our NetworkModuleSecond
?
Fortunately, Dagger has a solution for this.
The Solution
Step 1 :
First, we need to create a constructor for our module and pass the delay
as a constructor argument as shown below.
public class NetworkModuleSecond {
int delay;
public NetworkModuleSecond(int delay){
this.delay = delay;
}
@Provides
NetworkLayer provideNetworkSetupSecond(StorageLayer storageLayer){
return new NetworkSetupSecond(storageLayer, delay);
}
}
Step 2:
Don't forget to add this module to our component!
@Component (modules = NetworkModuleSecond.class)
public interface ComputeComponent {
//annotation processing
ComputeLayer getComputeLayer();
void inject (MainActivity mainActivity);
}
Step 3:
Let's build our project!
And we get an error!
It is basically telling us that we do not have the create method available anymore in our DaggerComputeComponent
class.
This is because the create
method is only available if none of our modules takes an argument in the constructor. The reason behind this behavior in Dagger 2 is rooted in how dependency injection works and the design principles of the Dagger framework.
When a module requires arguments in its constructor, it indicates that there's some external dependency or configuration that Dagger cannot automatically resolve. Dagger doesn't make assumptions about how to provide these external values. Instead, it requires the developer to explicitly provide them.
So, let's get go ahead and provide these external values to our dagger graph from the MainActivity
.
class MainActivity : AppCompatActivity() {
var calculate : Button? = null
var TAG = this.javaClass.canonicalName
@Inject
lateinit var computation : ComputeLayer
// var networkSetup: NetworkSetup? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
calculate = findViewById(R.id.calculate_sum)
//Notice how the create method is chaned with a builder method instead
val component = DaggerComputeComponent.builder().
networkModuleSecond(NetworkModuleSecond(1000)).build()
component.inject(this)
calculate?.setOnClickListener {
computation.add(1,1)
Log.e(TAG, "Button click detected")
}
Log.e(TAG, "Main Activity Created")
}
}
What we've done here, is that instead of letting Dagger2 create the NetworkModuleSecond
class, we created it on our own and passed the delay value as an argument.
And that's it! We have successfully injected a value to an object in our dagger graph at runtime!
Conclusion
Alright, we've had a good run exploring how to inject values into objects at runtime with Dagger2. But guess what? We're just scratching the surface here. Stick around for part 2 of this blog post, where we'll dive even deeper and have some more fun with Dagger2. See you there!