Hi I'm trying to create a fake presenter of my activity I have my module let's call it Activity1module where I have set all of the presenter, use-case, everything and it works perfect, but when trying to create a screen which uses that exact activity with a fake presenter it says I've bound multiple times that presenter.
What I've did is :
#Module
abstract class Activity1Module{
#Binds
abstract fun providePresenter(impl: PresenterImpl) : Activity1Contract.Presenter
.....
}
Then I have created a new module FakeActivity1Module and it's like this :
#Module(includes = [Activity1Module::class])
abstract class FakeActivity1Module {
#Binds
abstract fun bindsFakePresenter(impl: FakePresenterImpl): Activity1Contract.Presenter
.....
}
But looks like it doesn't like this way, is there any way to use the fake one instead of the production one without creating #Named or touching production code?
Dagger doesn't have any capability to have one module override another's bindings directly. FakeActivity1Module and Activity1Module should include similar bindings but neither should be in the other's includes list.
You can, however, extract common bindings to an Activity1CommonModule (named as you'd like) and have both Activity1Module and FakeActivity1Module include that module. That would allow you to avoid repeating yourself as much as possible, at the conceptual cost of some indirection between files.
You can even include that Activity1CommonModule as a nested interface (or abstract or static class) within Activity1Module; you'd still need Activity1Module's includes to contain its own Activity1Module.Activity1CommonModule.class, but you'd have the benefit of centralizing all of Activity1Module's bindings in a single file, plus the benefit of easily seeing through diffs (git diff, p4 diff, etc) when a binding moves in or out of the common set.
Same class cannot be injected 2 times and it produce bound multiple times error. So for the FakeActivity1Module instead of create new injection. Try to override Activity1Module and apply your changes.
class FakeActivity1Module: Activity1Module {
overrides fun providePresenter(): Activity1Contract.Presenter = FakePresenterImpl()
}
And you use FakeActivity1Module into your component for testing and it should work as expected.
Related
In my current Android project I have a feature A that display feature B, and now I need to be able to display feature A from feature B. Which create a circle feature dependency, generating a StackOverflow error on build time.
#Subcomponent(modules = [SubComponentA.Module::class])
interface SubComponentA {
fun plus(module: Module): SubComponentB
#dagger.Module
class Module {
// Provide stuff
}
}
-------------
#Subcomponent(modules = [SubComponentB.Module::class])
interface SubComponentB {
fun plus(module: Module): SubComponentA
#dagger.Module
class Module {
// Provide stuff
}
}
Is there a way to achieve this Dagger graph without a build time error?
Thanks!
If A produces B and B produces A, I imagine it would be difficult to get an instance of either one to act as the other's parent. That's not a problem, though: Dagger components do not have to represent the exact same ownership and access chain that your model objects or application UI represents. The important part of the Dagger graph is whether the objects you want are directly injectable and whether they have the correct Dagger-managed lifetime ("scope").
You clarified in the comments:
To add more context: Feature A is an article that can open another article or a Feature B, which is a detail view of a Hike. Inside the Feature B (Hike detail) we can access to an article (Feature A) and so on.
If the Article and Hike aren't directly related to each other in a nesting or ownership sense—you might start the app and navigate directly to either Articles or Hikes—then I would have the main Component act as the owner of both Subcomponents, such that neither Subcomponent is the parent of the other. Because Subcomponents can access all the bindings of their parent component tree, you'll be able to inject a SubcomponentA builder/factory1 from Component, SubcomponentA, or SubcomponentB, and you'll likewise be able to inject a SubcomponentB builder/factory from Component, SubcomponentA, or SubcomponentB. You won't be able to get to SubcomponentA bindings from SubComponentB (i.e. get to Article subcomponent Dagger bindings from the Hike subcomponent) or vice versa, but of course you can use a Module field or #BindsInstance binding to pass details about the Article or Hike you just navigated from. You could even pass the subcomponent instance itself, but in your position I'd probably just keep data model objects or identifiers to avoid keeping a long memory-expensive chain of objects.
If it is the case that Articles have zero or more Hikes and every Hike has exactly one Article, and that the Hike has reason to directly access all the Dagger bindings ("ArticleInteractionLogger", maybe) associated with its parent Article, then that's a good reason that SubcomponentB would be a subcomponent of SubcomponentA. However, then you won't be able to get to a Hike (SubcomponentB) instance without first getting an Article (SubcomponentA) instance, and navigating to a different Article means you would not inject the bindings directly from the Hike subcomponent you were just in.
All that said, it sounds like your motivation for subcomponents is cross-navigation, in which case I'd just leave the Dagger object graph out of it, have both Subcomponents installed on the parent Component, and save the history elsewhere—as subcomponent #BindsInstance fields or in a separate NavigationHistoryManager class of your own design.
Note 1: You're using the plus abstract factory method model from Dagger 1, but it is more idiomatic to define a Builder or Factory that you can directly inject. This avoids having to keep or inject the Component or Subcomponent instance directly to get to the plus method (which could be named anything). However, to use this you'll need to specify the Subcomponent in the subcomponents attribute of the #Module annotation for a Module on your parent Component.
#Subcomponent(modules = [SubComponentA.Module::class])
interface SubComponentA {
// Remove: fun plus(module: Module): SubComponentB
#dagger.Module class Module { /* ... */ }
#Subcomponent.Factory
interface Factory {
fun create(module: Module): SubComponentA
}
}
#Subcomponent(modules = [SubComponentB.Module::class])
interface SubComponentB {
// Remove: fun plus(module: Module): SubComponentA
#dagger.Module class Module { /* ... */ }
#Subcomponent.Factory
interface Factory {
fun create(module: Module): SubComponentB
}
}
I have the following module that is used in the data layer of my application which is a plain Android Library.
#Module
interface MapperModule {
#Binds
fun bindDomainToDataMapper(domainToDataMapperImp: DomainToDataMapperImp)
: DomainToDataMapper<TodoTaskEntity, ToDoTaskModel>
#Binds
fun bindDataToDomainMapper(dataToDomainMapperImp: DataToDomainMapperImp)
: DataToDomainMapper<ToDoTaskModel, TodoTaskEntity>
}
I am just wondering what the #InstallIn scope should be as this is the Data Layer so is not specific to any android components.
I was thinking of using #InstallIn(SingleComponent::class) but I don't want these classes to be singleton.
Any ideas of what this should be?
Hilt has predefined components for Android that are managed for you. However, there may be situations where the standard Hilt components do not match the object lifetimes or needs of a particular feature
Custom component limitations
Custom component definitions currently have some limitations:
Components must be a direct or indirect child of the
SingletonComponent. Components may not be inserted between any of the
standard components. For example, a component cannot be added between
the ActivityComponent and the FragmentComponent.
To create a custom Hilt component, create a class annotated with #DefineComponent. This will be the class used in #InstallIn annotations.
The parent of your component should be defined in the value of the #DefineComponent annotation. Your #DefineComponent class can also be annotated with a scope annotation to allow scoping objects to this component.
#DefineComponent(parent = SingletonComponent::class)
interface MyCustomComponent
A builder interface must also be defined. If this builder is missing, the component will not be generated since there will be no way to construct the component. This interface will be injectable from the parent component and will be the interface for creating new instances of your component. As these are custom components, once instances are built, it will be your job to hold on to or release component instances at the appropriate time.
Builder interfaces are defined by marking an interface with #DefineComponent.Builder. Builders must have a method that returns the #DefineComponent type. They may also have additional methods (like #BindsInstance methods) that a normal Dagger component builder may have.
#DefineComponent.Builder
interface MyCustomComponentBuilder {
fun fooSeedData(#BindsInstance foo: Foo): MyCustomComponentBuilder
fun build(): MyCustomComponent
}
While the #DefineComponent.Builder class can be nested within the #DefineComponent, it is usually better as a separate class. It may be separated into a different class as long as it is a transitive dependency of the #HiltAndroidApp application or #HiltAndroidTest test. Since the #DefineComponent class is referenced in many places via #InstallIn, it may be better to separate the builder so that dependencies in the builder do not become transitive dependencies of every module installed in the component.
For the same reason of avoiding excessive dependencies, methods are not allowed on the #DefineComponent interface. Instead, Dagger objects should be accessed via entry points.
#EntryPoint
#InstallIn(MyCustomComponent::class)
interface MyCustomEntryPoint {
fun getBar(): Bar
}
class CustomComponentManager #Inject constructor(
componentBuilder: MyCustomComponentBuilder) {
fun doSomething(foo: Foo) {
val component = componentBuilder.fooSeedData(foo).build();
val bar = EntryPoints.get(component, MyCustomEntryPoint::class.java).getBar()
// Don't forget to hold on to the component instance if you need to!
}
Conclusion:
Even if you create a custom component indirectly, it will look like a Singleton.
Even if you use #InstallIn(SingleComponent::class) without #Singleton annotation these object won' t be singleton. They will be non-scoped objects, and for every request, you will have new instance for these classes.
I was thinking of using #InstallIn(SingleComponent::class) but I don't want these classes to be singleton.
It means you can use #InstallIn(SingleComponent::class) without #Singleton annotation.
So I am currently in the process of learning dagger 2, and from the tutorials that I've read so far, for a dependency to be injected, the #Inject annotation gets placed inline with fields (for Activities/Fragments) or constructors. However I see that as an issue if I'm not the owner of parts of the code and can't add the required annotations for this technique to work, or if I don't want other parts of the code to know that dagger exists.
The application structure I have at the moment is:
App Module - where I'd like to put my DI code in (e.g. dagger modules, etc).
Presentation Module - Views/ViewModels etc.
Domain Module - Use Cases etc.
Data Module - Repositories etc.
With pretty much this style of classes contained in my application:
class ExampleViewModelImpl(useCase: ExampleUseCase): ViewModel() in Presentation (gets initialised from an Activity or similar).
class ExampleUseCaseImpl(repository: ExampleRepository): ExampleUseCase in Domain
class ExampleRepositoryImpl(dao: ExampleDao): ExampleRepository in Data
With the structure above, what is the minimum number of classes outside of the App Module that I need to touch in order to utilize dagger with as much automated dependency injection as possible? Code examples of how this is achieved would be great.
I am unsure of some terminologies, and wasn't able to find a solution online. If there are good resources which explains what I'm asking, that would also be great.
if I don't want other parts of the code to know that dagger exists.
#Inject is a standard (JSR 330) which Dagger implements. Adding those annotations doesn't have anything to do with Dagger and can be used the same way with other DI frameworks. If it's your code you should just add those #Inject annotations where appropriate. Think of them as documentation: What constructor/field/method must be injected to create & use this object?
The only place where your classes will know that Dagger exists is at the same place where you'd be creating the objects otherwise, too.
Going down that path, of course you could use Dagger without any #Inject annotations, but you'd be writing a lot of unnecessary boilerplate and missing out on the most powerful feature of Dagger at the same time (code generation).
#Inject annotation gets placed inline with fields (for Activities/Fragments) or constructors. However I see that as an issue if I'm not the owner of parts of the code and can't add the required annotations for this technique to work
That's what #BindsInstance with the #Component.Builder is for (add an object to the component) and what #Provides annotated methods are for (create and initialize an object from a module)
If you really want to write code without #Inject, then you'd do exactly this for all of your objects. This means a lot of modules, and even more #Provides annotated methods. It will work, but I don't see the point in writing all those methods if a single #Inject on the constructor has the same effect.
In my opinion the best thing about Dagger is that I can add / remove / change constructor parameters and don't have to touch any other parts of my code since Dagger will generate new code with the new arguments. In your case you'd have to also change the parameters to the #Provides method as well as the constructor invocation.
Next let's look at how to remove #Inject from fields. Basically you don't want to do field injection, so instead of writing an injection method in the component, you'd write provision methods.
#Component
class MyComponent {
fun inject(activity: MyActivity)
}
class MyActivity {
#Inject lateinit var myDep: Dependency
fun onCreate() {
component.inject(this)
}
}
Removing the #Inject we need to use the provision methods instead.
#Component
class MyComponent {
fun provisionMyDependency() : Dependency
}
class MyActivity {
lateinit var myDep: Dependency
fun onCreate() {
myDep = component.provisionMyDependency()
}
}
It will work and everything, but again, you will miss out on the single best feature of Dagger: Code generation. The example above looks alright because I only added a single dependency, but think about what happens to those 2 different implementations when you add / remove / change dependencies, how well it will scale. If you prefer to do things manually any refactoring will become arduous.
With the structure above, what is the minimum number of classes outside of the App Module that I need to touch in order to utilize dagger with as much automated dependency injection as possible?
Your question (especially the title) is in direct conflict with your goal. If you don't want to use those annotations, then you can't use Dagger code generation & injection but have to resort to do it manually as highlighted above.
with as much automated dependency injection as possible
To best utilize Dagger you add #Inject on the constructor and/or fields of every class that should end up on your dependency graph and let Dagger do its thing.
If we just use plain dagger 2. In the application class, we will have a property which holds the AppComponent. Then we can swap it during espresso tests.
But when I setup my project using dagger-android 2.15. Things becomes more implicit if adopt too much Dagger magic. The code is more clean, but makes testing a little bit hard.
This is the application class:
class App : DaggerApplication() {
override fun applicationInjector(): AndroidInjector<out DaggerApplication> {
return DaggerAppComponent
.builder()
.create(this)
.build()
}
}
This is the HomeActivity
class HomeActivity : DaggerAppCompatActivity() {
#Inject
lateinit var userPreference: UserPreference
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_home)
if (!this.userPreference.memberRegistered) {
goToActivity(EntryActivity::class.java)
}
}
}
Take this code for example. How to mock that injected userPreference.memberRegistered Which could be a HTTP call underneath?
For those who is interested in this, I got a blog with step by step detail for this:
Basically, the idea is:
You still generate instances for injection in #Module
But We’ll create new #Component A only for testing
This #Component will have a method to get that #Module
During tests, we swap the #Component that the application use with our component A
Then things are easy:
Without DaggerMock
In the #Module, instead of return real instance, you just return mockito mock.
With DaggerMock
You declare the type you want to swap and mock it
You can then use the mock.
No need to change the #Module
It inspires by #AutonomousApps 's solution, but the differences are now you don't need to write the #Component, #Module for each test class.
After trying several approaches, this is the only one that worked for me.
I wrote a blog post that explains how to do this just yesterday: https://dev.to/autonomousapps/the-daggerandroid-missing-documentation-33kj
I don't intend to repeat the entire post for this answer (it's hundreds of words and lines of code to properly set up a test harness with Dagger), but to attempt to summarize:
Add a custom application class in the debug source set (I assume it would also work in the androidTest source set, but I have not tried this).
You also need to reference this application in a AndroidManifest.xml in the same source set.
Create a "Test component" in your androidTest class that extends from your production top-level component and build it.
Use that test component to inject your application, which means you've just replaced your entire Dagger dependency graph with a new one you've defined just for the test suite.
Profit.
Using Dagger 2 in my android with MVP pattern, and struggling a little with some concepts.
Let's say I have a presenter DashboardPresenter, I am injecting it when I need it in an activity or other presenters, by using:
#inject
DashboardPresenter presenter;
or in the constructor of other presenters:
#inject
public AccountPresenter(DashboardPresenter presenter) {
//init
}
Now I'm not very sure how it works, but I want to do the following:
Let's say I create a BaseDashboardPresenter which will be the parent
And I create 2 children for it: NormalDashboardPresenter and ProDashboardPresenter both extends from it.
When I want to use it in an activity or another presenter, I inject the Base presenter by calling
#inject
BaseDashboardPresenter presenter;
And I override the #inject behavior, to inject one of the children based on a boolean.
So something like this:
//in BaseDashboardPresenter
override inject() {
if(Utility.checkIfUserIsPro()) {
inject ProDashboardPresenter();
} else {
inject NormalDashboardPresenter();
}
}
so from my activity I just call the abstract methods in the Base class, and the difference is only which child is injected.
Is this possible?
Happy to provide more clarification if needed.
Contrary to the other answer I believe that your modules should not include any logic. That's just not what one would expect.
Also, how would your #Provides method look if one variant needs A, while the other depends on B? Now you need to declare dependencies that you don't need and it just gets more confusing from here on.
Instead you should create one module for every option and include the correct module in your component.
// module providing pro version
componentBuilder.addPresenterModule(new ProModule());
// or a default one
componentBuilder.addPresenterModule(new DefaultModule());
That way wherever you build your component you get to decide what's supposed to be in it. An even more dedicated approach would be to use 2 completely different components where each component uses different modules etc. This might make sense for more complex projects, but in your case it seems that modules would be enough.
To do this, you should add in your module something like this:
#Provides
public BaseDashboardPresenter provideDashboardPresenter(OtherPresenter presenter) {
if (Utility.checkIfUserIsPro()) {
return new ProDashboardPresenter();
} else {
return new NormalDashboardPresenter(presenter);
}
}