Lazy Injection with Dagger 2 on Android - android

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.

Related

Dagger: How to check if dagger.Lazy variable has been initialised

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.

Should #Provides annotated method for Retrofit class be annotated with #Singleton

I have a Dagger2 #Module class with the #Provides annotated method which calls Retrofit.create method:
#Provides
RestService provideRestService(final Retrofit retrofit) {
return retrofit.create(RestService.class);
}
Should I annotate this method with the #Singleton annotation?
I see one reason to do it: calling create each time has some cost and one reason for not doing it: keeping one instance has some cost (Dagger performs double checking each time instance is requested).
Which solution is preferred? With or without #Singleton annotation? Or maybe it is not important at all? Or my approach to create this class in provider is fundamentally wrong?
If additional instances are allowed but potentially-expensive, you might also consider the use of #Reusable. You lose double-checked locking, but you (potentially) shorten object lifespans and gain flexibility about where the instances are installed.
#Reusable is useful when you want to limit the number of provisions of a type, but there is no specific lifetime over which there must be only one instance.
See the User's Guide topic or the SO question Dagger #Reusable scope vs #Singleton.
Yes, you should. You avoid memory allocation. Android will keep you the same instance untill the app is killed. Think about if you call the api like into a for loop and each time you create a new instance (not recommended and won't happen when you use dagger in same injectionm but just like an example). It will kill your memory. So you should use #Singleton.
Singleton will ensure you that you will use the same instance across module.

Using Dagger, is it ok to recreate an injected object?

A have code that is similar to this one:
class MyActivity extends Activity {
IStrategy mStrategy;
public void onCreate(Bundle data) {
if (someSpecificCondition) {
mStrategy = new StrategyA();
} else {
mStrategy = new StrategyB();
}
}
public void onUnsupportedState() {
// Will have to switch strategy
mStrategy = new StrategyB();
}
}
I would like to inject IStrategy here. But I have two problems:
It is an interface and the concrete implementation changes dynamically.
Even after a concrete implementation is chosen, there is the possibility that it will need to be recreated.
I could overcome (1) by creating a provides method with the decision logic (not sure if it is the best approach though).
But I am not sure what to do with (2).
Is it ok to manually create an injected object in this case? Does anyone see another solution?
As you said, adding logic to provider method is not a good design decision. Manually instantiating the object is valid in some cases, but only as a last resort.
In this case, the best approach (IMHO) is to inject abstract factory that instantiates IStrategy implementations on demand.
In the current state of the matters, the factory method will need to accept additional parameter that allows you to specify which strategy you're interested in. While it is not the end of the world, the fact that the client controls which strategy it uses is a bit unclean - the client knows how many strategies are there.
Depending on the specific use case at hand, you might be able to refactor the code and extract the logic that differentiates between strategies out of the client. That way your client will be asking for IStrategy while being completely agnostic of both the specifics of the implementation, and the number of available implementations.

should presenters(mvP) be injected(dagger2) to views in android?

In the context of developing and android app, should I use presenters directly in views using 'new' or would it be better if I injected them to the view.
Pros/cons for not using injected presenters:
Faster development time, without having to write components and modules.
Presenters are tightly coupled with the views, I don't see this as much of a problem as most of the time presenters are not shared across multiple views(ie. one single view for a presenter).
Might be a problem for testing, as with using dependency injection mock implementations of the presenters can be provided(not sure if this is any useful, need more insight on this).
You're right. Using injection will only help you in the long run. You could either spend 5 minutes setting up your module / component, or you could be just coding.
As long as you don't do proper testing, there is not much difference to it, if you presenter looks like the following
mPresenter = new Presenter();
Assuming you use constructor injection properly, after creating your component, you save some lines as compared to
#Inject Presenter mPresenter;
// onCreate or some other place
{
getComponent().inject(this); /* getComponent() also 4-5 lines */
}
Again. If you use proper constructor injection there is a good chance you don't have many module code. Just creating some component will do.
But you saved some minutes and once you want to do testing this is just some easy refactoring, which can quickly be done.
So why Dagger?
This was assuming your presenter has no dependencies on other objects. But what if it does?
SharedPreferences preferences = getPreferences();
MyStorage storage = new MyStorage(preferences);
mPresenter = new Presenter(storage);
Using something to store your data is properly a good use case. While you just added some more logic about object creation to your activity, the dagger implementation would still look the same.
Even more?
Now let's assume you want to share this storage from above between activities. Now you have to add some logic to your Application or in some other place where you can create a Singleton to use throughout your app.
This will probably not be your only singleton, though, and you will start to clutter up your Application as well. Don't get me started on managing those objects lifecycle, e.g. user logging in or out, make sure to clear that cached data!
Again. The dagger implementation still looks the same. If there is some more logic needed it is well placed in the modules and abstracted with component dependencies.
Once you start thinking I could just create classes that handle object construction and injection you know that you could have just used dagger in the first place ;)
I also wrote a blog post about dagger basics including how constructor injection works, which many beginners are not using properly for some reason.

#Injects after #Produces?

I'm trying to learn DI through Dagger 2 and apply it to our product. The Application-level things annotated with #Singleton are straightforward enough (e.g. SharedPreferences). In thinking of our architecture, there are several dependencies that are asynchronous in nature which I've imagined scoped at a #ForSession scoping.
Our authentication token/account info, acquired from the Android AccountManager. Could be synchronous in the case of an existing, valid session. Could be asynchronous if no existing session and the AccountManager has to show the complete the login flow.
Once we have a valid session token and session information:
Provide an Endpoint to fulfil dependencies so that our networking layer knows where to find the API.
acquire our "user" information from a network API.
pull additional supporting information from a network API (or local cache).
pull localized back-end strings from a network API (or local cache).
Get a component going that relies on a bound Service. Provide that component asynchronously only when the bound Service binding is complete.
The presentation layer should be gated on the receipt of the collection of these items. Aside from some sort of "loading" display, there's not much it can do without any of the above.
It feels like these dependencies fit the use-case for #ProducerModule and #Produces. I feel like I could have #Produces ListenableFuture<> methods for each of these dependencies, with perhaps a SettableFuture<> as the implementation. Perform whatever work is required, call set() on that future, dependency is met.
Where I get antsy is with this quote from the Producers guide.
As in the above example, producer modules can be used seamlessly with ordinary modules, subject to the restriction that provided types cannot depend on produced types.
For the "gate presentation on everything being available" I can envision a composite object that could get #Inject with the unwrapped T of the futures. But is that even legal?
This is the closest I've come but it's explicitly calling the constructor of the composite, not injecting it. Is there a way to do this cleaner?
#ProducerModule
public class SessionModule {
#Produces
#ForSession
static ListenableFuture<User> produceSignedInUser(SessionManager sessionManager) {
return sessionManager.getSignedInUserFuture();
}
#Produces
#ForSession
static ListenableFuture<BoundService> produceBoundService(SessionManager sessionManager) {
return sessionManager.getBoundServiceFuture();
}
#Produces
#ForSession
static CompositeSessionInfo produceComposite(User user, BoundService service) {
return new CompositeSessionInfo(user, service);
}
}
Then the component:
#ForSession
#ProductionComponent(modules = SessionModule.class)
public interface SessionComponent {
ListenableFuture<CompositeSessionInfo> getCompsiteSessionInfoFuture();
}
And somewhere I want to gate I can do something like:
SessionComponent component = Dagger_SessionComponent.builder()
.executor(executor)
.build();
Futures.addCallback(component.getCompsiteSessionInfoFuture(),
new FutureCallback<CompositeSessionInfo> {
public void onSuccess(CompositeSessionInfo result) {
releaseTheHounds(result);
}
public void onFailure(Throwable t) {
reportError(t);
}
});
Am I way off on my understanding of this part of it? And an aside: why are the #Produces methods declared static? Is this required? (EDIT: the static sure isn't required, but I'm unsure what the intent was other than to not have instance fields in the Module).
EDIT:
I decided to create a proof of concept project to abstract out my ideas from my actual project. Everything works as I'd like except that I'm unable to #Inject any of my #Produced items, either the end result "composite" data or intermediate results. If I expose a getter in the component, I can get them so that's what I've done.
My current plan is to have this #Producer based asynchronous stuff off in a separate injectable module, then have the resultant dependencies get fed into a #Provides style module that feeds elsewhere so that they can be #Injected.
EDIT EDIT:
Updated the proof of concept to have a common precursor dependency to more closely mimic my needs. Still can't #Inject. I believe this about as good as I'll get.
Alright, since it appears I'm going it alone I'll post my final conclusions as my own answer to hopefully help out someone else looking to do something similar.
I updated my proof of concept project one more time. Now, once all of the asynchronous dependencies are met the new single composite dependency is an actual #Module, #Produced by the newly renamed SessionProductionComponent, then that module is registered as a component called the SessionProvisionComponent. This component is a standard #Component with #Provide methods to provide dependencies through the standard #Inject mechanism.
#Produces
#ForSession
public SessionProvisionModule produceSessionProvisionModule(Application app, SomeAsyncDependency someAsyncDependency, AnotherAsyncDependency anotherAsyncDependency) {
SessionProvisionModule module = new SessionProvisionModule(someAsyncDependency, anotherAsyncDependency);
((App) app).createSessionProvisionComponent(module);
return module;
}
Now in the MainActivity, when I need to acquire the session information it looks like so:
App app = (App) getApplication();
sessionProductionComponent = app.getSessionProductionComponent();
if (app.getSessionProductionComponent() == null) {
sessionProductionComponent = app.createSessionProductionComponent(new SessionProductionModule());
}
Futures.addCallback(sessionProductionComponent.getSessionProvisionModuleFuture(),
new FutureCallback<SessionProvisionModule>() {
#Override
public void onSuccess(SessionProvisionModule result) {
app.getSessionProvisionComponent().inject(MainActivity.this);
}
#Override
public void onFailure(Throwable t) {
// handle failure
}
});
Once the Future succeeds I can inject() the MainActivity and any annotated fields get #Injected with dependencies as one would expect.
In this way, I can actually have #Inject after #Produce.
Not as clean as I'd like, but still better than without DI. Now any number of asynchronous dependencies, operating on whatever timeframe, can be satisfied in any order and once all of them are ready a single Future is set and a SessionProvisionComponent is made ready to inject dependencies with those #Produced dependencies.
Mostly happy.

Categories

Resources