Im trying to do a very simple dependency injection in a Android app. I am using dagger 2 as a DI tool.
The issue is no injection is occuring:
here is my code:
//behold Motor.java in all its awe.
public class Motor {
private int rpm;
public Motor(){
this.rpm = 10; //default will be 10
}
public int getRpm(){
return rpm;
}
public void accelerate(int value){
rpm = rpm + value;
}
public void brake(){
rpm = 0;
}
}
and here is the Vehicle.java which utilities the motor class:
import javax.inject.Inject;
public class Vehicle {
private Motor motor;
@Inject
public Vehicle(Motor motor){
this.motor = motor;
}
public void increaseSpeed(int value){
motor.accelerate(value);
}
public void stop(){
motor.brake();
}
public int getSpeed(){
return motor.getRpm();
}
}
I then created a VehicleModule.java class to define my provider:
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
@Module
public class VehicleModule {
@Provides
@Singleton
Motor provideMotor(){
return new Motor();
}
@Provides @Singleton
Vehicle provideVehicle(){
return new Vehicle(new Motor());
}
}
I then i have a interface component annotated, defined like this:
import javax.inject.Singleton;
import Modules.VehicleModule;
import dagger.Component;
@Singleton
@Component(modules = {VehicleModule.class})
public interface VehicleComponent {
Vehicle provideVehicle();
}
and here is my Android mainactivity class that should be injected but its not, can anyone help:
import javax.inject.Inject;
public class MainActivity extends ActionBarActivity {
@Inject
Vehicle vehicle;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toast.makeText(this, String.valueOf(vehicle.getSpeed()), Toast.LENGTH_SHORT).show();
}
}
im getting a null pointer exception on vehicle:
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'int com.example.uen229.myapplication.Vehicle.getSpeed()' on a null object reference
by the way my gradle dependencies look like this:
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:22.2.0'
compile 'com.google.dagger:dagger:2.0'
}
You're expecting magical things happen when you annotate something with
@Inject
. While magical things will happen, it's not that magical. You will need to do that yourself, by instantiating the component implementations that Dagger generated.You can do this in a couple of ways, I will describe two.
First, in your
MainActivity
'sonCreate
:In this case, you create an instance of
VehicleComponent
, implemented by Dagger, and fetch theVehicle
instance from it. Thevehicle
field is not annotated by@Inject
. This has the advantage that the field can beprivate
, which is a good thing to want.Secondly, if you do want Dagger to inject your fields, you need to add an
inject
method to yourVehicleComponent
:In your
MainActivity
class, you callinject(this)
, which will fill thevehicle
field:This brings a bit of extra configuration, but is sometimes necessary. I like the first method however.
As a final comment, let's have a look at your
VehicleModule
, and really use the power of Dagger.Instead of using the module to create the instances yourself, you can make Dagger to that for you. You've already annotated the
Vehicle
constructor with@Inject
, so Dagger will know to use this constructor. However, it needs an instance ofMotor
, which it doesn't know of. If you add an@Inject
annotation to the constructor ofMotor
as well, and annotate theMotor
class with@Singleton
, you can get rid of theVehicleModule
altogether!For example:
Your
Vehicle
class:You can now safely delete the
VehicleModule
class, and remove the reference to it in yourVehicleComponent
.