Question

Trying to use dagger dependency injector for Android. This is extended Application class:

public class MyApplication extends Application {

    private ObjectGraph objectGraph;

    protected List<Object> getModules() {
        List<Object> objectArrayList = new ArrayList<Object>();

        objectArrayList.add(new AndroidModule(this));
        objectArrayList.add(new DeviceModule());

        return objectArrayList;
    }

    @Override
    public void onCreate() {
        super.onCreate();

        objectGraph = ObjectGraph.create(getModules().toArray());
    }

    public void inject(Object object) {
        objectGraph.inject(object);
    }
}

This my modules:

AndroidModule

@Module(library = true)
public class AndroidModule {
    private final MyApplication myApplication;

    public AndroidModule(MyApplication myApplication) {
        this.myApplication = myApplication;
    }

    @Provides
    @Singleton
    @ForApplication
    public Context provideApplicationContext() {
        return myApplication.getApplicationContext();
    }

    @Provides
    @Singleton
    public LocationManager provideLocationManager() {
        return (LocationManager)myApplication.getSystemService(Context.LOCATION_SERVICE);
    }

    @Provides
    public NetworkInfo provideNetworkInfo() {
        ConnectivityManager connectivityManager = (ConnectivityManager)myApplication.getSystemService(Context.CONNECTIVITY_SERVICE);
        return connectivityManager.getActiveNetworkInfo();
    }
}

DeviceModule

 @Module(injects = MainActivity.class, complete = false, library = true)
public class DeviceModule {

    @Provides
    public SystemValidator provideSystemValidator() {
        return new AndroidSystemValidator();
    }

    @Provides
    public Device provideDevice(SystemValidator systemValidator) {
        return new Device(systemValidator);
    }
}

Device class

public class Device {
    private final SystemValidator systemValidator;

    @Inject
    public Device(SystemValidator systemValidator) {
        this.systemValidator = systemValidator;
    }

    public void validate() {
        boolean isGPSTurnedOn = systemValidator.isGPS();
        boolean isNetworkActive = systemValidator.isNetwork();
    }
}

SystemValidator class

public class AndroidSystemValidator implements SystemValidator {
    @Inject
    LocationManager locationManager;

    @Inject
    NetworkInfo networkInfo;

    @Override
    public boolean isNetwork() {
        return (null != networkInfo && (networkInfo.getType() == ConnectivityManager.TYPE_MOBILE));
    }

    @Override
    public boolean isGPS() {
        return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
    }
}

This piece of successfuly compiles, but on runtime I get java.lang.StackOverflowError trying to inject MainActivity object into ObjectGraph

java.lang.StackOverflowError
        at com.xxxx.app.modules.system.DeviceModule$$ModuleAdapter$ProvideDeviceProvidesAdapter.get(DeviceModule$$ModuleAdapter.java:77)
        at com.xxxx.app.modules.system.DeviceModule$$ModuleAdapter$ProvideDeviceProvidesAdapter.get(DeviceModule$$ModuleAdapter.java:113)
        at com.xxxx.app.modules.system.DeviceModule$$ModuleAdapter$ProvideDeviceProvidesAdapter.get(DeviceModule$$ModuleAdapter.java:77)
        at com.xxxx.app.modules.system.DeviceModule$$ModuleAdapter$ProvideDeviceProvidesAdapter.get(DeviceModule$$ModuleAdapter.java:113)
        at com.xxxx.app.modules.system.DeviceModule$$ModuleAdapter$ProvideDeviceProvidesAdapter.get(DeviceModule$$ModuleAdapter.java:77)
        at com.xxxx.app.modules.system.DeviceModule$$ModuleAdapter$ProvideDeviceProvidesAdapter.get(DeviceModule$$ModuleAdapter.java:113)

EDITED:

Code was changhed by working solution but even though LocationManager and NetworkInfo objects are marked by @Inject, are null. Tried to tell AndroidModule where to place these object by adding injects = AndroidSystemValidator.class but didn't work out. How can I inject these objects without creating paramatrized construtor?

Was it helpful?

Solution 2

I think you issue is with

 @Provides
 public Device provideDevice(Device device) {
     return device;
 }

Where does the device come from? You need to make a new instance at that point.

For your Device and AndroidSystemValidator, I think you should inject them using the constructor. If you want to use Dagger to do this for you do something like

@Inject public Device(SystemValidator systemValidator) {
  this.systemValidator = systemValidator;
}

Otherwise use the modules similar do what you have just change to

@Provides
public Device provideDevice(SystemValidator systemValidator) {
    return new Device(systemValidator);
}

OTHER TIPS

You have a cyclic dependency in

@Provides
public Device provideDevice(Device device) {
    return device;
}

When Dagger tries to obtain a Device instance to use as an argument for provideDevice method it invokes provideDevice for it again and again so far the StackOverflowError occurs. But it's only my assumption.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top