I got a very useful blog to start my hand with Dagger2. All going I guess going pretty well except an deprecate warning about to Builder.addModule().
I got this link about Unused Modules and Component Dependencies link related but it still not clear to me.
When the Dagger processor generates components, it only requires
instances of modules and component dependencies that are explicitly
needed to supply requests for a binding.
Any one know if any alternative of this deprecated method ?
Related
Square Inc. has presented it's internal modular architecture at Droidcon SF'19:
https://www.droidcon.com/media-detail?video=380843878
However, I'm a bit confused with some bullets. Could you please help me?
Why do they actually need :wiring modules? I find it adding complexity:
you get extra gradle module for each new feature
you have to make a sort of global injection into your Fragments somewhere in :app, because Fragments defined in :impl modules cannot access it's DaggerComponent, which is defined in :impl-wiring modules. :impl doesn't depend on :impl-wiring, because the dependency is reversed.
you cannot have an Android Dynamic Feature modules, because they should know about it's DaggerComponent in order to inject it's Fragment. But there is no way to do such injection from :app module, which is base-module for Dynamic Features.
so why :wiring modules at all?
One can merge :impl and :impl-wiring, or :fake and :fake-wiring together to eliminate all the issues mentioned above. And also, in :demo-apps one could just have a dependency on either :impl or :fake``, and not on :impl-wiring(or:fake-wiring```).
The creation of this type of modules is to separate even more. With this you generate an abstraction of the type of component you use (koin, dagger) and how. If the project is large, it makes sense to do it.
Currently I generate the following flow of dependencies between modules:
WARNING: Check the directionalities well.
:feature-A:open <- :feature-A:impl -> :feature-A:impl-wiring
:feature-A:impl-wiring -> :feature-A:impl, :feature-A:open
:app -> :feature-A:open, :feature-A:impl-wiring
I'm still not sure if app should depend on open and impl-wiring, or which app should only depend on open and open from impl-wiring.
Eventually, I came up with the following solution:
each feature consists of the following gradle-modules:
api
impl and fake
data:api
data:impl1 ... data:implN and data:fake
data:wiring
ui
demo
So, here api, impl and fake as usual, but I've my data layers separated. I bought myself that I need multiple different implementation of data layers sometimes, for example - if I develop Stock-Charts App, I could rely on Finnhub Open API or MBOUM API or provide fake implementation.
Thus I have data:api, data:implX. Indeed, data:api defines FeatureRepository interface (one or many) and data:implX provides actual implementation for them. In order to bind interface and implementation, I use data:wiring, which defines Dagger modules and component(s). In addition, I keep the same package names within each data:implX module in order to "write-once" the data:wiring module. And to replace one implementation with another, I just change a single line in data:wiring/build.gradle which states a sort of:
implementation project(":data:implA")
to
implementation project(":data:implB")
Also, to break the confusion mentioned in my original question, I introduce ui module, which contains some Views of a particular feature. Fragments go in demo (a standalone app to test feature) or in ui, they refer to viewModel which have some bindings ctor-injected from Dagger component of a feature. But the UI and library are separated here. Fragment instantiates a dedicated Dagger component that uses component dependencies to refer to feature's library bindings, such as interactor or repository etc.
So, to wrap up - separation between UI and business logic implementation (a "library") for each feature makes it possible to solve the issue. Feature's api declares an entry point to it's functionality as a library, and it's global access via Dagger multibindings from :app. So it can be used further in any :demo, :ui and :dynamic-feature.
In Clean Architecture, Robert Martin says:
It is in your Main component that dependencies should be injected by a
Dependency Injection framework. Once they are injected into Main, Main
should distribute those dependencies normally, without using the
framework.
Martin, Robert C.. Clean Architecture (Robert C. Martin Series) (p.
232). Pearson Education. Kindle Edition.
However, Dagger doesn't work this way. Once you set up your dependencies in your application, you still need to depend on it as a framework, e.g. write #Inject annotations to get the dependencies into your classes. There is no way to 'distribute these dependencies' normally, by which I assume he means passing them through a constructor?
Can anyone help clear up my understanding and how best to use Dagger with a Clean style?
On Android, exactly following the advice you quoted from Robert Martin is rather difficult.
This is because there is no precise main entry point. Application, Service and Activity are quasi-entry points as your app will start with the OS instantiating one of these.
However, you don't have control over the constructor or anything really before the lifecycle callbacks. Hence, Dagger 2 on Android has had to rely on manually calling requesting a Component and calling Component#inject() inside lifecycle callbacks quasi-entry points.
However, there have been some measures to address this problem. Dagger-Android goes some way to address this by making you depend on AndroidInjector rather than some series of calls to the Application in order to retrieve the Component manually.
Even further, there is now FragmentFactory that allows control over the constructor of a Fragment, making Fragments amenable for constructor injection. If we use this then we have gone some way to following Robert Martin's advice.
To clarify the original quotation, I believe Robert Martin means that classes apart from the component root should not be polluted with logic for obtaining dependencies (e.g., by reaching into the Application, pulling out the Dagger Component). He is not prohibiting the use of the #Inject annotation which is lightweight meta-data (part of JSR-330) that simply marks a constructor as a site for injection.
In summary, yes - the current way of using Dagger 2 on Android doesn't exactly comply with Robert Martin's excellent recommendation. Nevertheless, this is a known problem and some progress has been made towards solving it.
I have a main application which uses Dagger (some previous version) for providing dependencies.
Now, I am writing an SDK where I am using (Dagger 2.10+). Every thing works fine, when I have an application class, as applications has (HasActivityInjector) and it's responsible for the initialization of DaggerAppComponent.
My Question is -
Should I use Dagger 2 in my sdk (I want to as it makes my code more testable)
If not, then I am considering writing my own Injection class.
If I go for it, how should I initialize at the application level as the only solution for this I found out was to have an Application class in sdk and make client extend it. (I dont want this change at client side and not a good design).
Any suggestions would be great!!
I recently had to tackle the same issue: Create an SDK that can be used in any supported Android App.
I did have to accept the premise that some of the of the Apps that would want to use the SDK won't themselves be using Dagger or even dependency injection.
The major issue with creating an SDK that uses dependency injection is, as OP has pointed out, the Application implementation in the App.
Part of the reason behind the creation of the HasActivityInjector, HasFragmentInjector or HasSupportFragmentInjector has been the need to comply with the following dependency injection rule:
A class shouldn’t know anything about how it is injected. Reference A
With the creation of the HasXInjector interfaces, Android allows the the Dagger Dependency Graph to be attached to the Application, and then for the Application to be responsible for injecting the dependencies where they need to be injected through the following code:
AndroidInjection.inject(this) // <-- 'this' being an Activity or Fragment
SDK ISSUE
The issue is that the SDK does not have an Application implementation of its own. Additionally, the SDK can not add anything to the Application implementation of the App, nor can it override the Application implementation of the App.
In the case of an external SDK, it will not even know about an Application implementation, just the Application Interface.
So even if the Application that has included the SDK uses Dagger, which is not guaranteed, the SDK will not be able to add it's Dependency Graph to the Dependency Graph used by App's Application implementation, making all SDK dependencies unreachable.
And if the Application does not use Dagger, how would the dependencies be injected in the first place?
My own solution to this issue has been to break the rule quoted above and not use the HasActivityInjector, HasFragmentInjector or HasSupportFragmentInjector for injection internally in the SDK.
I would be creating a library (.aar) at my current workplace. It has a lot of complicated business processes and would definitely need a lot of automated tests, due to which I was planning on using dagger in my library.
But as it is a library, it needs to be as small as possible and depend on as fewer dependencies as possible. Not to mention that dagger just bloats anything it is used with.
So, I am in crossroads and unable to decide what should be my approach.
Can someone please help me come to a conclusion.
there isnt any problem with using dagger in a library if you use the dagger just inside. i mean as long as you dont expect the user of that to provide some dependencies for you from out of the library.
dagger makes the code complicated but not for yourself. assume the person who uses the library knows nothing about DI or dagger.
I myself have some project including a library using a dagger and even needing some dependencies to be provided from out of the library but since the whole project is mine and im not gonna export the library everything is ok.
so this depends how you gonna use it and i suggest if you wanna give this library to others dont expect them to implement dagger and provide some dependencies for you.
While reading the docs for dagger 2 I cannot find an easy way to provide a dependency when building an app for testing. The only clue I've found is this:
Dagger 2 doesn't support overrides. Modules that
override for simple testing fakes can create
a subclass of the module to emulate that behaviour.
Modules that use overrides and rely on dependency injection
should be decomposed so that the overridden modules are instead
represented as a choice between two modules.
I don't understand how I would set up such a configuration on Android, anyone can explain?
This is currently impossible with Dagger 2 (as of v2.0.0) without some workarounds. You can read about it here.
I've proposed one workaround but this requires changes to the production code.
In short:
provide additional setter for #Component (e.g. in Android setter in Application class)
test component must extend the production component
For more information please check both links. Hope this issue will be addressed in future versions of Dagger 2.