I understand that constructor injection should be preferred whenever possible, but for theoretical understanding, I want to learn more about field and method injection.
Method injection apparently is very rare, and according to Jake Wharton, the only use-case for it is when you have to pass an instance of your dependent object to the dependency (because it might be not fully instantiated in the constructor yet).
Example for method injection:
#Inject
public void enableStreaming(Streaming streaming) {
streaming.register(this);
}
The field & method injection process into a dependent object can be triggered in 2 ways:
Either in combination with constructor injection, in which case
it is executed automatically after the constructor ran (no need to call inject on a component). This is what is happening in the example
above (I omitted the constructor, imagine it as being #Inject annotated)
Without constructor injection, when the object is already instantiated.
In this case, we need a members-injection method where
we pass the object. The fields/method will then be injected when we
call component.inject(object) This is most commonly used for
field-injection in activities and fragments.
What I am asking for, are examples for the opposite cases.
Do you have examples for when field injection is combined with
constructor injection?
Do yo you have examples for when method injection is not combined
with constructor injection (and therefore needs an explicit inject call)?
For both cases, I would like to know if there are situations when
the component.inject() method is called from the outside or from within the object and what are use-cases for this. Is there ever a
scenario where we call
ExampleObject exampleObject = new ExampleObject();
component.inject(exampleObject);
to execute field or method injection on exampleObject?
I don't have published or official examples handy, but all of the situations you described work fine. It is unusual for field injection to be combined with constructor injection, because the fields are necessarily non-final to work with field injection where they could be final if passed through a constructor. It is less-unusual to see method injection without constructor injection, for similar self-registration cases to the enableStreaming method you wrote above, but that is still somewhat of an unusual use-case.
Though field and method injection may take place within the method or class being injected, this would necessitate receiving a specific Component instance or a MembersInjector<T> for your class T, which is at least as much trouble to call as component.inject(exampleObject) in your third example above. After all, the whole point of dependency injection is to allow the caller to control the class's dependencies, so it is arguably a weakening of DI for the owning class to take control of whether and how its dependencies are provided.
The only cases I can think of where a class would manage its own injection is if your class wanted to conditionally inject itself—if (BuildOptions.FEATURE_X_ENABLED) { injector.inject(this); }—but many other patterns spring to mind that would manage that type of case better.
Related
I found the answer for Kotlin Lazy objects, using isInitialized() here: Kotlin: Check if lazy val has been initialised
But seems like dagger.Lazy doesn't have the same public method.
This is how I lazily inject using Dagger:
#Inject internal lateinit var someService: dagger.Lazy<SomeService>
How to check if someService is already initialized without calling someService.get() which will initialize it? Other than introducing a boolean flag and keep track of it ourselves..
Thanks!
There isn't a way to check; Lazy only has one method, get, making it a functional interface or "Single Abstract Method (SAM)" interface much like JSR330's Provider, Guava's Supplier, and JDK8 Supplier.
This abstraction is important, because in Dagger the definition of Lazy is more complicated and there is more than one implementation. For scoped bindings, the internal InstanceFactory itself implements Lazy, so the built in Provider<Lazy<T>> available for each T in the graph can be implemented using a class ProviderOfLazy that can simply return the internal Provider or InstanceFactory rather than creating a new wrapper instance. With that in mind, the instance of Lazy you interact with might be a shared one, so a hypothetical isInitialized might be ambiguous: Does it mark that the scoped binding was ever accessed, or just the local Lazy injection point you requested? Would that behavior change based on whether you mark the binding scoped or not in a faraway Module file? You could also imagine an implementation where every Lazy injection got its own instance, and each would locally track whether it had ever had its get called regardless of scoping. This is in contrast to Kotlin's Lazy, in which each instance wraps exactly one initializer function and consequently has less ambiguity.
Also, Kotlin's Lazy has multiple synchronization modes from which you can select, some of which have undefined behavior when called concurrently. isInitialized is never synchronized in any of those modes, so in a concurrent environment you might receive false while the value is in mid-construction, or it may even be fully constructed on a different thread and the value is simply not yet visible from the thread calling isInitialized.
If you need to be able to check on a Lazy-like status, you'll need to specify how wide you care about construction and how thread-safe you want the result to be, which is custom enough to warrant your own implementation.
I am new to Dagger, though I understand that injection can be achieved in two ways(as far as I can conclude) that by injecting constructor using #Inject and by using #Provide in the Module.
Still my conclusion doesn't have a valid point wrt to realtime scenarios and example.
Any suggestions will be helpful. Thank You
Yes, there are two types of injection, Constructor and Field injection.
Annotating fields for injection tells dagger to inject the proper object into them.
Annotating constructor for injection tells dagger to inject required objects and also allows dagger to create an instance of the class if it was needed somewhere else.
On the other hand, there is #Provide which is something different. with 'Provide' you provide dagger with required objects and dagger will inject them wherever they are needed. You define how to instantiate an object for injection.
Curious question, I'm using ButterKnife and I just discovered you can't use in private methods because ButterKnife creates classes that use them. Doesn't that violates the principle of encapsulation? I mean, then your variables will be exposed to other classes as well, no?
You are totally right, using Butterknife violates the principle of encapsulation.
Butterknife uses its own generated code to perform view look-ups. And those look-ups are done in separate class(-es) hence the fields cannot be private.
Quote:
The generated code exists in a class outside of this class, thus the
fields are truly being accessed outside of the class, hence not
private. If you see other generated code that is accessing private
fields, it is using reflection to by-pass the private access
restriction, which means you have fields that look private but are
actually being accessed outside of the class.
Using reflection would not only be the same thing under the hood but also significantly slower compared to view look-ups.
Anyway, those classes that use Butterknife to perform view binding should not be initialized anywhere apart of classes that are responsible for the same thing (view binding, that is) so violating encapsulation is not a big deal. For example: Activities can have instances of Fragments, Fragments/Activities can have instances of RecyclerViewAdapters because all of these are responsible for view binding, but ViewModel (MVVM architecture) for example should not have an instance of Fragment/Activity or any View in general because it has nothing to do with view binding.
Good luck. :)
I’m new to Dagger 2. I have this scenario, I wan't to inject an object across my app (in presenters, in api)
I do not have a way to provide it initially. It is not created till after authentication at some stage in my app.
From the documentation http://google.github.io/dagger/
I see Lazy loading might be a way to solve this e.g
#Inject
Lazy<Grinder> lazyGrinder;
and then get the value like this using:
lazyGrinder.get().grind();
My questions are:
Can I safely swap the object after this with a new one?
Are there any other recommended ways to do this?
Thanks
This isn't a good match for Lazy. Lazy is a great way to delay expensive object initialization, but it implies some semantics that you don't want or need, particularly regarding the "safely swap" behavior you want.
To put it simply, Lazy is a Provider wrapper that memoizes locally:
If you never call get, Dagger never creates the object in question.
The first call to get creates and stores the object instance.
The second call to get returns the same instance, and so on forever, regardless of whether the object was marked as Singleton.
This makes Lazy an excellent choice for an expensive object that would otherwise be a field (but may never be used). However, if the reference is likely to change (as your will), Lazy will simply be confusing: It will store the value at first use and never locally update, so multiple out-of-date copies might be floating around in your application regardless of what the "right" value is at any given time.
To borrow the use of Grinder from your example, better solutions include:
Using a #Provides method that returns a field in a Module, which can be updated later. You'll need to inject Provider<Grinder> for every long-lived object instance, because injected references to Grinder alone won't update. This still might be the best bet if you have a lot of short-lived objects.
The reference is implicitly singleton, but is not annotated as such, because you're controlling the instance yourself. Dagger will call your getGrinder method frequently.
#Module public class YourModule {
private Grinder grinder;
public void setGrinder(Grinder grinder) {
this.grinder = grinder;
}
#Provides public Grinder getGrinder() {
return grinder;
}
}
/* elsewhere */
YourModule module = new YourModule();
YourComponent component = DaggerYourComponent.builder()
.yourModule(module)
.build();
/* ... */
module.setGrinder(latestAndGreatestGrinder);
As EpicPandaForce mentioned in the comments, create/bind a singleton GrinderHolder, GrinderController, or AtomicReference object that provides the current instance and allows for updating. That way it's impossible to inject a Grinder directly, but easy and obvious to inject the object that fetches the current correct Grinder. If your singleton GrinderHolder implementation doesn't create the Grinder until the first time you ask for it, then you have effectively created a Lazy singleton on your own.
If you aren't able to provide the object at the time of Component creation, don't add it to your Component graph! That is asking for confusing graph dependencies and inconsistency. A better solution to what you are considering is a #Subcomponent approach, which allows you to create a new component which inherits the dependencies from the parent, but also adds new one. Here's an example:
#Component
interface RegularComponent {
#AppInstanceId String appInstanceId(); // unique per app install; not related to logging in
AuthenticatedComponent newAuthenticatedComponent();
}
#Subcomponent
interface AuthenticatedComponent {
Set<Friend> friends();
#AccountId String accountId();
}
Here, the #AccountId in the subcomponent could use the appInstanceId to provide the account ID (if it needed to) since the Subcomponent shares dependencies with its parent component.
If you need to supply state to your modules for the subcomponent (with the accountId, auth token, etc) feel free to pass it in as a parameter to the #Module and store it in a private final field. You can read more on how to supply subcomponent modules in the documentation.
I came across the dagger library from Square and I'm currently making some tests. I'm new to the DI principle so be kind :)
So, I understand Dagger can inject fields and constructors. I'm also aware that in my activities, I have to .inject(this); so that injection can be done at runtime.
But what about an object O that needs to be created after the activity initialization ?
If O has injectable fields, I have to .inject(O); before using it otherwise I get a NullPointerException when accessing its injected variables. But if I write a injectable constructor, no problem, no runtime exception.
Of course I wrote my #Module according to the documentation.
Isn't it the purpose of Dagger to injects fields with no other code to write ? Do I have to manually .inject(); all my objects ? There is for sure a thing I'm missing.
Thanks in advance.
As you wrote Dagger supports two kind of injection:
field injection
constructor injection
In the first case you create an object then you inject the fields using inject method. For example in your onCreate of an Activity you will call this:
mObjectGraph.inject(this);
The second type of injection (constructor injection) requires that the object is created by Dagger. You simply mark the constructor with #Inject annotation then you can create instance like this:
HasInjectableConstructor instance = mObjectGraph.get(HasInjectableConstructor.class);
That's it. Maybe Dagger 2 will change something in this matter: squ.re/dagger2