1

I want to ask how to do the injection of a constructor that doesn't have any parameters. I have come across this problem but unable to find a solution. Here is my repo class

public class UrlsRepository {

    private UrlsSource urlsSource;

    @Inject
    public UrlsRepository(UrlsSource urlsSource){
        this.urlsSource = urlsSource;
    }

    public String getLandingUrl(){
        return urlsSource.getLoginUrl();
    }

    public String[] getDashboardUrls(){
        return urlsSource.getDashboardUrls();
    }
}

Here is the interface

public interface UrlsSource{
    String getLoginUrl();

    String[] getDashboardUrls();
}

and below is the implementation

@Singleton
public class LocalUrlsSource implements UrlsSource {

    @Inject
    public LocalUrlsSource(){}

    @Override
    public String getLoginUrl() {
        return Properties.LOGIN_URL;
    }

    @Override
    public String[] getDashboardUrls() {
        return Properties.DASHBOARD_URLS;
    }
}

Now inside my main activity, I'm injecting UrlsRepository but it's null. Please guide.

public class MainActivity extends Activity implements MainPresenter.View {

    @Inject
    UrlsRepository urlsRepository;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);
    }
}
eC Droid
  • 651
  • 2
  • 9
  • 26
  • I don't see `AndroidInjection.inject(this)` in your main activity? – Bach Vu Jun 25 '19 at 07:12
  • I'm not injecting any of the android component i.e activities or fragment. Hence AndroidInjection doesn't work for my case. – eC Droid Jun 25 '19 at 07:13
  • If Dagger doesn't _create_ the object (constructor injection vs the Android framework creating your Activity) then you will have to manually inject the object using a component (usually the `component.inject(this)` call you see in examples) after the object has been created. Dagger generates code for `@Inject` annotated fields, but this code needs to be invoked, too. – David Medenjak Jun 25 '19 at 07:16
  • @DavidMedenjak but in my case I can't use a component because I don't have any module to provide my dependency. Or may be you can post the code snippet for it if I'm missing something. – eC Droid Jun 25 '19 at 07:18
  • Without `module` and `component`, how do you expect Dagger2 to work? :D – Bach Vu Jun 25 '19 at 07:21
  • @BachVu the `UrlsRepository(UrlsSource urlsSource)` has a dependency of `UrlsSource` interface which is being provided by the `class LocalUrlsSource implements UrlsSource` class which has a default constructor only. My scenario doesn't requires any module. @DavidMedenjak – eC Droid Jun 25 '19 at 07:24
  • @DavidMedenjak please suggest. – eC Droid Jun 25 '19 at 07:32
  • 1
    @eCDroid See my answer below, maybe it helps. – Ludvig W Jun 25 '19 at 09:26

1 Answers1

1

If you wan't to inject interfaces like this you need to create a @Module with a @Binds annotated method like this.

@Module
abstract class UrlModule {

    @Binds
    abstract UrlsSource bindUrlsSource(LocalUrlsSource source);
}

And then you would create a component which uses this module and inject into your activity.

@Component(modules = {UrlModule.class})
@Singleton
public interface AppComponent {

    void inject(MainActivity activity);
}

Then initiate the component in your Application.java class and retrieve it inside your activity and call inject(), for example like this.

public final class MainApplication extends Application {

    private static AppComponent appComponent;

    public static AppComponent getAppComponent() {
        return appComponent;
    }

    private static AppComponent createAppComponent(Application application) {
        return DaggerAppComponent.create();
    }

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

        appComponent = createAppComponent(this);
    }
}

Then you would inject the dependency like this.

public class MainActivity extends Activity implements MainPresenter.View {

    @Inject
    UrlsRepository urlsRepository;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        // Injects this activity.
        MainApplication.getAppComponent().inject(this);
    }
}
Ludvig W
  • 744
  • 8
  • 27
  • Thanks for the answer. Would you mind explaining the purpose of @bind? – eC Droid Jun 25 '19 at 09:53
  • 1
    @eCDroid Great! Here is a great post which explains the difference between Provides and Binds. https://stackoverflow.com/questions/52586940/what-is-the-use-case-for-binds-vs-provides-annotation-in-dagger2 – Ludvig W Jun 25 '19 at 10:55