How to use AndroidInjector.Factory? - dagger-2

I'm migrating from Dagger 2.21 and Builder is changed to Factory. How is AndroidInjector.Factory supposed to be used? I have this component
interface AppComponent : AndroidInjector<MainApplication> {
#Component.Factory
interface Factory : AndroidInjector.Factory<MainApplication> {
fun create(#BindsInstance emailId: String) : AppComponent
}
}
But it fails with "error: #Component.Factory types must have exactly one abstract method. Already found: create(T)".
AndroidInjector.Factory already seems to have a create which binds MainApplication instance. How am i supposed to bind another value? The only workaround i found is not to extend from AndroidInjector.Factory like this but then why have AndroidInjectory.Factory?
interface AppComponent : AndroidInjector<MainApplication> {
#Component.Factory
interface Factory {
fun create(#BindsInstance instance: MainApplication,
#BindsInstance emailId: String) : AppComponent
}
}

You don't need (and as you noticed you actually can't) to extend AndroidInjector.Factory when you have additional parameters needed to create the component.
You should extend AndroidInjector.Factory when you are using dagger-android to inject dependencies into android components using AndroidInjection.inject(). To make this injection possible you need to follow some rules, in particular your component's factory should extend AndroidInjector.Factory.
AndroidInjector.Factory defines AndroidInjector<T> create(#BindsInstance T instance), which will be used by dagger-android to instantiate this subcomponent, so you can't add any additional parameters.
Update:
Dagger and dagger-android are two different libraries. Dagger is a general DI framework, it does not contain any android-specific code. Component.Factory comes from dagger itself and you are free to add a method with any number of parameters, which will be used to create your subcomponent.
Dagger-android in its turn is an android-specific library which greatly reduces boilerplate code that you need to write by generating it. But you loose some flexibility and have to follow the structure defined by the library. Here your factory method cannot have any additional parameters and the factory should extend AndroidInjector.Factory.
Generally you can also mix both approaches in one project, but I would not recommend to do so to make your code consistent.

Related

Dagger 2 inject subcomponent.builder

I'm seeing some code where a SubComponent.Builder is being injected. For instance:
class MyClass #Inject constructor(val mySubcomponentBuilder: MySubComponent.Builder) {
fun someFunc(knownAtRuntime: String) {
mySubcomponentBuilder.withSomethingIKnowAtRuntime(knownAtRuntime).build()
}
}
Why do we (and where/when should we) do this (i.e. inject subcomponent.builders)?
Is this sort of like assisted injection where we can provide instances that are needed on the graph that we only know during runtime?
Yes, a subcomponent builder is sort of like assisted injection, but for a whole subgraph of injectable Dagger dependencies.
What are subcomponents?
Subcomponents are additional components that derive from parent components. In Guice they are analogous to child injectors; in Dagger 1 they are analogous to subgraphs. They let you add additional bindings on top of the parent bindings, as specified through additional modules.
In the sense that they allow bindings from different graphs, they can be compared to component dependencies, but they are generated at the same time as the parent component and can transparently use bindings defined in the parent component. The dagger.android and Hilt packages both use subcomponents.
Each component can have their own scope, and subcomponents aren't an exception: you might see a #Singleton ApplicationComponent with a subcomponent of #RequestScope RequestComponent for servers or #ActivityScope ActivityComponent for Android. Each request or activity would get their own component instance. That would let you inject a #RequestScoped MetricsService or #ActivityScoped User, which would be the same instance within the same request/activity but different instances between the requests/activities.
What are subcomponent builders?
Subcomponents might require modules to be instantiated if they have non-empty constructors, or they might require instances to be bound through #BindsInstance. Subcomponent Builders allow you to specify those just like you would for a Component Builder.
You also have the choice of using a Subcomponent.Factory, analogous to Component.Factory but with all of the Builder parameters as the arguments to one method call.
Why would I inject subcomponent builders? What are the alternatives?
Though you can declare subcomponents as factory methods specified on the parent component, this prevents Dagger from pruning unused dependencies because it can't see who is requesting the subcomponent. By declaring subcomponents on modules and injecting their builders into the graph, Dagger can remove entire subcomponents if you don't call them at all.

Resolving to parent interface during constructor injection

This involves autofac and c#. I have an interface derived from a parent interface:
public interface IJ4JLogger<out TCalling>
{
}
public interface IJ4JSmsLogger<out TCalling> : IJ4JLogger<TCalling>
{
}
Certain classes depend on being supplied an instance of the parent interface during construction:
public FileHistoryConfiguration( IJ4JLogger<FileHistoryConfiguration> histLogger, IJ4JLogger<FileHistoryService> svcLogger )
{
}
But if I register the type like this with autofac:
builder.RegisterGeneric( typeof(J4JSmsLogger<>) )
.As(typeof(IJ4JSmsLogger<>))
.SingleInstance();
where J4JSmsLogger<> is a class implementing IJ4JSmsLogger<>, then this call fails with an error that it can't find anything registered to provide an IJ4JLogger<> interface:
_fhConfig = _svcProvider.GetRequiredService<IFileHistoryConfiguration>();
I can work around the problem by changing the As<> clause in the registration of J4JSmsLogger<> to treat it as a IJ4JLogger<> instance, and then cast the result of resolving that interface to IJ4JSmsLogger<> whenever I need the extra capabilities of the child interface.
But I don't understand why I have to do that. Is there an additional step I need to take during registration of the types with autofac so that objects implementing the child interface will satisfy a need for the parent interface?
Cleaner Workaround
Reading more about autofac I learned something new: you can define as many As<>() clauses (including AsSelf()) as you want. So changing my autofac configuration to:
builder.RegisterGeneric( typeof(J4JSmsLogger<>) )
.As(typeof(IJ4JSmsLogger<>))
.As(typeof(IJ4JLogger<>))
.SingleInstance();
provides a cleaner solution than constantly casting resolved instances.
I'm not going to submit it as an answer, though, because I am curious why autofac doesn't do this kind of downcasting automatically, and whether any other DI frameworks do.
Autofac won't cast to base types for you like that. It generally assumes wiring is exact. You could run into some real problems if it didn't, like if someone has a constructor like...
public class BadTimes
{
public BadTimes(object input) { }
}
Which object does it put in there? Everything casts down to object.
However, you could always register it as both types and call it a day:
builder.RegisterGeneric(typeof(J4JSmsLogger<>))
.As(typeof(IJ4JSmsLogger<>))
.As(typeof(IJ4JLogger<>))
.SingleInstance();

Why Dagger Component requires #Scope annotation

When you want to provide scoped dependency, Dagger requires to annotate Component with this Scope too. What is the reason for that?
#Singleton // <- for what?
#Component(modules = [MyModule::class])
interface MyComponent {
//...
}
#Module
interface MyModule {
#Binds
#Singleton
fun provideDependency(impl: DepImpl): Dep
}
Scoping in Dagger means "give this binding the same lifetime as the component that contains it", so the component itself holds onto the instance so it can provide the same instance repeatedly.
Components are also hierarchical: through subcomponents and component dependencies you can have multiple components coexisting in the same application. In a typical Android app, you might have an Application component that provides bindings for several Activity components, and and each of those Activity components provides bindings for several Fragment components.
Though Dagger could theoretically infer scopes based on which module installs it, instead of requiring you to specify which scope applies to which component, this makes it more difficult to work with classes that declare scope and #Inject annotations without an explicit Dagger binding. If you're in an Activity component that inherits bindings from an Application component (often "singleton"), and an Activity binding relies on an #ApplicationScope-annotated class with an #Inject constructor, how would Dagger know to put it in the Application component instead of the Activity component? This might also make your code harder for humans to understand—I know I'd have trouble following it.

In Dagger, does an Inject annotated class also act as a Provider?

I am new to Dagger (version 2.16 on Android) and based on my reading so far, I understand that for a component, there should be a provider (#Provides or #Binds) encapsulated in a module (#Module). Going through a lot of samples, I see code which has some objects which are not offered in any Module, nor are they being instantiated using new.
It is also my understanding that in order to access the dependencies in a module, a consumer class needs to inject itself in the component graph (components usually offer a method to inject classes). The code examples are not doing this either.
Here's some code demonstrating both my concerns. RecipePresenter is not being provided in any module, but still RecipeActivity is using it.
A possible explanation I could think of is that #Inject, in addition to requesting the dependency also adds/injects the requesting class (RecipePresenter in the linked code) into the component graph. But assuming there are multiple components/subcomponents, which component does the class using #Inject constructor gets attached to? If my understanding is correct, why do activities and fragments have to inject themselves manually in the component - shouldn't they be auto-injected if they declare a variable annotated with #Inject?
RecipePresenter has an #Inject-annotated constructor, which allows it to be provided. The #Inject annotation on the recipePresenter field within RecipeActivity does not help, just the #Inject-annotated constructor.
class RecipePresenter #Inject constructor(
private val useCase: RecipeUseCase,
private val res: StringRetriever) :
RecipeUseCase.Callback {
From the Dagger User's Guide:
Use #Inject to annotate the constructor that Dagger should use to create instances of a class. When a new instance is requested, Dagger will obtain the required parameters values and invoke this constructor.
If the class with the #Inject-annotated constructor also has a defined scope, then the binding will only affect components with the same scope annotation: An #ActivityScope class wouldn't be accessible from a #Singleton component, for instance. If the class has no scope defined, then the binding could appear on any and all components where it is needed, which is fine: The implementation is always the same, defined by the constructor itself.
#Inject has different meanings based on what it's annotating:
When you annotate a field with #Inject, it indicates that the DI system should set that field based on values from the DI system when it injects that object.
When you annotate a method with #Inject, it indicates that the DI system should call that method with parameters based on values from the DI system when it injects that object.
When you annotate a constructor with #Inject, it indicates that the DI system is allowed to call that constructor in order to create that object (which triggers the field and method injection above). In that sense it does act like a built-in Provider.
In Dagger specifically, #Provides methods take precedence over #Inject constructors (if they both exist for the same class), and unlike in the JSR-330 spec Dagger requires an #Inject-annotated constructor even when no other constructors are present. From the Dagger User's Guide:
If your class has #Inject-annotated fields but no #Inject-annotated constructor, Dagger will inject those fields if requested, but will not create new instances. Add a no-argument constructor with the #Inject annotation to indicate that Dagger may create instances as well.
Classes that lack #Inject annotations cannot be constructed by Dagger.
Finally, to answer your question about why activities and fragments need to inject themselves: Android is allowed to reflectively create Activity/Fragment/View objects without Dagger's help or participation. This means that nothing triggers the field and method injection described above, until you call a members-injection method on the component that instructs Dagger to populate those fields and call those methods. Consequently, you should never see an #Inject-annotated constructor on Application, Activity, Service, Fragment, View, ContentProvider, and BroadcastReceiver subclasses in Android: Android will ignore the #Inject annotation, so you might as well take control over injection yourself, manually or through dagger.android.

Making a subcomponent inherit depedencys from different components

Lately i've been working a lot with Dagger 2 and I'm having this particular use case that I'm not able to do the way I want to for different reasons:
1) It's not possible; 2) I'm just not understanding the concepts behind scopes and components/subcomponents.
I have 3 Components: AppComponent, DBComponent, ActivityComponent.
I need to have my activity to inherit dependencies from AppComponent and DBComponent. This is my following setup:
AppComponent:
#Singleton
#Component(modules = { AppModule.class }) {
EventBus bus()
ActivityComponent plus(ActivityModule activityModule);
}
DatabaseComponent:
#Database
#Component(dependencies = AppComponent.class, modules = DatabaseModule.class) {
ActivityDependency activityDependency();
}
ActivityComponent:
#PerActivity
#Subcomponent(modules = ActivityModule.class) {
void inject(MainActivity activity);
}
When I inject bus() everything works fine but as soon as I try to inject ActivityDependency() it simply does not work. I cannot figure out why...
Please note: I've read about almost all the posts in here and outside explaining scopes, components and subcomponents and still I can't get my head wrapping around how to achieve what I wanted.
Note 2: I know one way to fix this which is to add DatabaseModule.class as a module in the AppComponent and remove DatabaseComponent from the equation. But I feel this will make AppComponent with too much information and this is not really the go to way.
inherit dependencies from AppComponent and DBComponent.
Wrong. You need to inherit dependencies from AppComponent, and the contents of the DBComponent should be a module of AppComponent.
Note 2: I know one way to fix this which is to add DatabaseModule.class as a module in the AppComponent and remove DatabaseComponent from the equation. But I feel this will make AppComponent with too much information and this is not really the go to way.
Yes, it is the go-to way if you're using scoped dependencies.
Think of dependency inheritance like the extends keyword in Java.
You cannot extend multiple classes with the same class, can you?
Similarly, you cannot extend multiple scoped components either.
So if you want your graph to provide bindings for a given scope, then your component needs to have all the modules for that given scope. And #Database isn't really a scope (think lifecycles), that's a renamed #Singleton.