dagger2 constructor injection how to provide dependency without module - android

I've read that constructor injections don't require a module.
So I have this questions.
If I have this constructor injection:
private Model realmModel;
#Inject
public MainActivityPresenter(Model realmModel) {
this.realmModel = realmModel;
}
and this component:
#Singleton
#Component(modules = {AppModule.class})
public interface AppComponent {
Model realmModel();
void inject(MainActivity activity);
}
if in my MainActivity I do it:
((MyApp)getApplication()).createAppComponent().inject(this);
how could I pass the realmModel parameter to the presenter constructor injection?
EDIT: this is the model:
Presenter presenter;
#Inject
public RealmModel(Presenter presenter) {
this.presenter = presenter;
}
Thanks

Three ways to solve this problem
1) Give a module which does the provide of the Relam Model
#Provides
#Singleton
public Model providesRealmModel() {
return new Model();
}
2) Make your RelamModel class also constructor injected
class Model {
#Inject
public Model() {}
}
The Trick in construction injection is all its dependencies should also be constuctor injeceted then it would work fine.
(From experience your model would need application context. look at the 3 option for ways to implement external Dependencies
3) Provide Model as external dependency.
#Module
public class ModelModule {
private Model relamModel;
public ModelModule(Model relamModel) {
this.relamModel = relamModel
}
}
#Component(module={ModelModule.class})
public interface ApplicationComponent {
}
Take a look at the series of videos from twisted eqautions these were my first video tutorial on dagger2. I found it really helpful. Hope it helps you too
https://www.youtube.com/watch?v=Qwk7ESmaCq0

You have two choices:
use a module with a provide method
annotate the constructor of Model with #Inject, doing that when you pass realmModel in the presenter contructor, the model
constructor will be called.
I prefer to use modules, but that's just my opinion.

Related

Dagger 2 how to access same component everywhere

How do I create a singleton object that I can access anywhere from any place in my code?
Objects(1) from which I want to inject my signleton component can't be created withing dagger.
Those objects don't have common dependencies which I can access (like getApplication()
Quick to an example:
InjectedClass:
public class InjectedClass {
public InjectedClass() {
System.out.println("injected class created");
}
}
HolderClassA:
public class HolderClassA { // this is one of object I marked with (1)
#Inject InjectedClass b;
public HolderClassA() {
Injector build = DaggerInjector.builder().build();
build.inject(this);
System.out.println(b);
}
}
HolderClassB:
public class HolderClassB { // this is another object I marked with (1)
#Inject InjectedClass b;
public HolderClassB() {
Injector build = DaggerInjector.builder().build();
build.inject(this);
System.out.println(b);
}
}
Provider:
#Module
public class Provider {
#Provides
#Singleton
InjectedClass provideInjectedClass() {
return new InjectedClass();
}
}
Injector:
#Component(modules = {Provider.class})
#Singleton
public interface Injector {
void inject(HolderClassA a);
void inject(HolderClassB a);
}
Somewhere in code:
new HolderClassA();
Somewhere else in code that is NO WAY related to previous code, nor has the same parent or can access same objects (like in dagger guide with getApplication()):
new HolderClassB();
Actual result: two instances of InjectedClass are crated
Expected result: a single instance of InjectedClass is created.
The issue is DaggerInjector.builder().build(); creates different scopes which don't know about each other. For example, I can solve this issue by creating static variable DaggerInjector.builder().build() and call inject from it. But thus it wouldn't be dependency injection anymore, but rather not trivial singleton pattern.
From what I understand from comments, you want separate components for your holder classes, that would inject same instance? Pardon me if I am wrong.
You can try this.
#Component(modules = arrayOf(AppModule::class))
#Singleton
interface AppComponent {
//sub components
fun plusHolderClass1(holderModule: HolderModule1):HolderComponent1
fun plusHolderClass2(holderModule: HolderModule2):HolderComponent2
//provision methods
fun getInjectedClass():InjectedClass
}
This is your application component, or the top level component, that you initialise in your application, of course using your Module class that will provide the Injected class as a singleton.
#Subcomponent(modules = arrayOf(HolderModule1::class))
#ActivityScope
interface HolderComponent1{
fun inject(holder:Holder1)
}
And a similar one for Holder2 class. You can define your local scope dependencies in the modules.
But of course even in this case you have to store the instance of appComponent in Application class.
While injecting
appComponent.plusHolderComponent1(HolderModule1()).inject(yourObject)
The InjectedClass object will be injected to yourObject by fetching it from provision methods

How to declare dependencies

I'm studying Dagger 2 so I would like to understand some basic things. I have the following code:
#Module
public class MainModule {
#Provides
public Presenter provideMainActivityPresenter(Model model){
return new MainPresenter(model);
}
#Provides
public Model provideMainModel(){
return new MainModel();
}
}
and my MainPresenter class looks like this:
public class MainPresenter implements Presenter {
#Nullable
private ViewImpl view;
private Model model;
public MainPresenter(Model model) {
this.model = model;
}
#Override
public void setView(ViewImpl view) {
this.view = view;
}
}
Instead of the above code, could I do the following?
public class MainPresenter implements Presenter {
#Nullable
private ViewImpl view;
#Inject
Model model;
#Override
public void setView(ViewImpl view) {
this.view = view;
}
}
Because the MainPresenter depends on the Model and it is not #Nullable.
Or this is wrong?
I don't understand when I should put a dependency as a constructor argument, or when I should use #Inject
You have basically 3 ways to use Dagger
Constructor injection
Field injection
Providing it from a module yourself
(There is also method injection which calls a method after creating your object)
The following is using a module that provides your class. While not wrong, this is the most overhead to write and maintain. You create the object by passing in the requested dependencies and return it:
// in a module
#Provides
public Presenter provideMainActivityPresenter(Model model){
// you request model and pass it to the constructor yourself
return new MainPresenter(model);
}
This should be used with things that require additional setup, like Gson, OkHttp, or Retrofit so that you can create the object in one place with the required dependencies.
The following would be used to inject objects where you don't have access or don't want to use the constructo. You annotate the field and register a method at the component to inject your object:
#Component class SomeComponent {
void injectPresenter(MainPresenter presenter);
}
public class MainPresenter implements Presenter {
// it's not annotated by #Inject, so it will be ignored
#Nullable
private ViewImpl view;
// will be field injected by calling Component.injectPresenter(presenter)
#Inject
Model model;
// other methods, etc
}
This will also provide you with overhead to register all your classes at a presenter and should be used when you can't use the constructor, like Activities, Fragments, or with Services. That's why all those Dagger samples have those onCreate() { DaggerComponent.inject(this); } methods to inject parts of the Android framework.
Most importantly you can use Constructor Injection. You annotate the constructor with #Inject and let Dagger find out how to create it.
public class MainPresenter implements Presenter {
// not assigned by constructor
#Nullable
private ViewImpl view;
// assigned in the constructor which gets called by dagger and the dependency is passed in
private Model model;
// dagger will call the constructor and pass in the Model
#Inject
public MainPresenter(Model model) {
this.model = model;
}
}
This only requires you to annotated your class constructor and Dagger will know how to handle it, given that all the dependencies (constructor arguments, Model in this example) can be provided.
All of the methods mentioned above will create an object and can / should be used in different circumstances.
All of those methods either pass the dependencies to the constructor, or inject #Inject annotated fields directly. Dependencies should thuse be in the constructor or annotated by #Inject so that Dagger knows about them.
I also wrote a blog post about the basic usage of Dagger 2 with some further details.

Dagger - Getting Same Instance On Different Component

I'm having a similar problem like the one in this question.
While the accepted answer does help, but I'm missing final piece to solve the problem.
I have 2 android library modules: common and exp which depends on common.
Everything under common:
#Module
public class CommonModule {
#Singleton
#Provides
public Repository providesRepository() {
return new Repository();
}
}
#Singleton
#Component(modules={CommonModule.class})
public interface CommonComponent {
void inject(CommonClass commonClass);
/**
CommonClass needs instance of Repository
**/
}
public class CommonDIHolder {
public static CommonComponent sComponent;
public static void init() {
sComponent = DaggerCommonComponent.builder().build();
}
}
Everything under exp:
#Module(includes={CommonModule.class})
public class ExpModule {
#Singleton
#Provides
public ExpResource provideExpResource() {
return new ExpResource();
}
}
#Singleton
#Component(modules={ExpModule.class}, dependencies={CommonComponent.class})
public interface ExpComponent {
void inject(ExpClass expClass);
/**
ExpClass needs instance of Repository and ExpResource
**/
}
public class ExpDIHolder {
public static ExpComponent sComponent;
public static void init() {
sComponent = DaggerExpComponent.builder()
.commonComponent(CommonDIHolder.sComponent)
.build();
}
}
I need both CommonClass and ExpClass receive the same instance of Repository.
The problem with this approach is that #Singleton can't depends on #Singleton. So I have to change the scope of ExpComponent into self-defined scope called #ExpScope. Then I changed the provideExpResource into #ExpScope as well.
Then I encountered an error saying that ExpComponent may not reference bindings with different scopes. It refers to the provideRepository which has different scope (#Singleton) on it. If I changed the scope into ExpScope then the CommonComponent will have different scope with provideRepository.
If I changed all #Singleton into #ExpScope then I receive this error message: depends on scoped components in a non-hierarchical scope ordering
What should I do? Or I'm doing the wrong approach here?
Use one and only one #Singleton scoped component
You should have one and only one #Singleton scoped component like this:
#Singleton
#Component(modules={CommonModule.class, ExpModule.class})
public interface CommonComponent {
}
Only specify Activities, Fragments, and Services as explicit injection targets for Components
In an Android app, you should only list Activities, Fragments and Services as injection sites. You should configure Dagger 2 to inject the rest of your dependencies without having to resort to calling component.inject(this) inside them.
For example, if your CommonClass looks like this:
public class CommonClass {
#Inject Repository repository;
public class CommonClass() {
CommonComponentHolder.get().inject(this);
}
}
Refactor it like this:
public class CommonClass {
private final Repository repository;
#Inject
public class CommonClass(Repository repository) {
this.repository = repository;
}
}
Now when you have an Activity or Fragment that needs CommonClass and you are injecting with CommonComponent or one of its sub-components or dependent components, they can obtain instances of CommonClass wired with the correct dependencies:
public class MyActivity extends AppCompatActivity {
#Inject CommonClass commonClass;
public void onCreate(Bundle savedInstanceState) {
CommonComponentHolder.getComponent().inject(this);
}
}
Use subcomponents or dependent components to specify the injection targets
Now you have a #Singleton scoped component, you'll probably want to create a component for a narrower scope for your Activity or Fragment. You'll have to connect it to your CommonComponent, so use dependent components or subcomponents (subcomponents are preferred as of Dagger 2.10). Since you say you have already tried defining a #ExpScope, I think the missing piece is to make subcomponent or dependent component with the #ExpScope that injects your Activity or Fragment.
Something like the following for the top-level singleton component:
#Singleton
#Component(modules={CommonModule.class, ExpModule.class})
public interface CommonComponent {
ExpComponent.Builder exComponent();
}
And then for the subcomponent:
#ExpScope
#Subcomponent(modules = {NarrowerScopedModule.class})
public interface ExpComponent {
#Subcomponent.Builder
public interface Builder {
Builder narrowerScopedModule(NarrowerScopedModule narrowerScopedModule);
ExpComponent build();
}
}
There are good working examples of Android projects in the Google Android Architecture Blueprints Github repo

Dagger 2 How to create a Module for Base Activity Components and a separate Module for all MVP components

Hello I am new to Dagger2.
Goal. Take my Networking DI and MVP DI. MVP as in the presenter for an an activity that extends base activity. I want to combine all this into one super module and place this into my base activity. Over time add more presenters.
I do not want 30+ inject statements in my baseActivity.
I am following this example but it is too simple compared to what I am trying to do.
I think the issue is with injecting the API at the base activity. For some reason Dagger is looking for Api in my MVP class.. So that would be a dependency graph issue?
Having spent more time on this.. The issue stems from Mvp's interface of baseActivity or any sub activity that extends baseActivity. That means when it goes to inject, it sees the #inject Api call, and cannot find it. It will work if I add Api to this module, but thats upside down of what I want. I want Component / Module for Application level items. I then want a component / module that has all my different MVP component in one module.. It's like Dagger starts looking for dependencies in the leaf of a tree and getting upset when it doesn't see whats in the root. I need it to go the other way. Be satisfied that I injected the dependency in the Root activity.
Base Activity...
#inject
public ApiClient mClient;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mManager = new SharedPreferencesManager(this);
DaggerInjector.get().inject(this);
}
DaggerInjector
public class DaggerInjector {
private static AppComponent appComponent = DaggerAppComponent.builder().appModule(new AppModule()).build();
public static AppComponent get() {
return appComponent;
}
}
#Component(modules = {AppModule.class, ApiModule.class, MvpModule.class})
#Singleton
public interface AppComponent {
void inject(BaseActivity activity);
}
Api
#Singleton
#Component(modules = {ApiModule.class})
public interface ApiComponent {
void inject( BaseActivity activity);
}
#Module
public class ApiModule {
#Provides
#Singleton
public ApiClient getApiClient(){
return new ApiClient();
}
}
Mvp
#Singleton
#Component(modules = {MvpModule.class})
public interface MvpComponent {
void inject(BaseActivity activity);
}
#Module
public class MvpModule {
#Provides
#Singleton
public MvpPresenter getMvpPresenter(){ return new MvpPresenter();}
}
Error:(16, 10) error: ApiClient cannot be provided without an #Inject constructor or from an #Provides- or #Produces-annotated method. This type supports members injection but cannot be implicitly provided.
ApiClient is injected at
...BaseActivity.ApiClient
...BaseActivity is injected at
MvpComponent.inject(activity)
I found out my problem. I needed to use a subcomponent.
#Singleton
#Subcomponent(modules = {MvpModule.class})
public interface MvpComponent {
void inject(BaseActivity activity);
}
#Module
public class MvpModule {
#Provides
#Singleton
public MvpPresenter getMvpPresenter(){ return new MvpPresenter();}
}
see
Dagger- Should we create each component and module for each Activity/ Fragment
Dagger2 activity scope, how many modules/components do i need?

Dagger 2 - modules from different components

I am not quite sure how to solve this with dagger 2.
Lets assume we have ApplicationModule that provides us ApplicationContext
then we have ApplicationComponent that uses just this one module.
Then on top of it we have ActivityModule and ActivityComponent that has dependency on ApplicationComponent.
ActivityComponent is build just like
ApplicationComponent component = ((MyApplication) getApplication()).getComponent();
mComponent = Dagger_ActivityComponent.builder()
.applicationComponent(component)
.activityModule(new ActivityModule(this))
.build();
And then I inject my activity:
mComponent.inject(this);
Now I am able to use everything that is declared inside my ActivityModule, however it is not possible for me to access ApplicationModule.
So the question is how could that be achieved? So that when I build component that depends on another component I can still access module from the first one?
EDIT
I think I have found solutions, after rewatching Devoxx talk by Jake again, I have had to miss that out, whatever I want to use from another components module I have to provide in that component, for example I want to use Context from ApplicationModule then inside ApplicationComponent I have to state Context provideContext(); and it is going to be available. Pretty cool :)
You have already answered your question, but the answer is to specify the provision methods in your "superscoped" component (ApplicationComponent).
For example,
#Module
public class ApplicationModule {
#Provides
#Singleton
public Something something() {
return new Something.Builder().configure().build();
// if Something can be made with constructor,
// use #Singleton on the class and #Inject on the constructor
// and then the module is not needed
}
}
#Singleton
#Component(modules={ApplicationModule.class})
public interface ApplicationComponent {
Something something(); //PROVISION METHOD. YOU NEED THIS.
}
#Scope
#Retention(RetentionPolicy.RUNTIME)
public #interface ActivityScope {
}
#ActivityScope
public class OtherThing {
private final Something something;
#Inject
public OtherThing(Something something) {
this.something = something;
}
}
#Component(dependencies = {ApplicationComponent.class})
#ActivityScope
public interface ActivityComponent extends ApplicationComponent { //inherit provision methods
OtherThing otherThing();
}

Categories

Resources