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

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.

Related

Why when we init dependency in module we waiting for interface type and not actual object type? - Android

Please someone explain me why when we use dependency injection and initialize the object in the module the provides function return type is interface but in body function we return the actual object. This is example
#Provides
#Singleton
fun providePrefsManager(#ApplicationContext context: Context): PrefsManager {
return PrefsManagerImpl(context)
}
Why here we return PrefsManager instead of PrefsManagerImpl ?
Code to the interface, not the implementation. #Provides methods provide according to their return values, so if you return PrefsManagerImpl, Dagger will only know how to inject PrefsManagerImpl. By returning PrefsManager, Dagger lets you inject PrefsManager directly, so the injecting class doesn't need to be aware of PrefsManagerImpl or any other implementation at all.
More specifically to dependency injection: The concept behind dependency injection is that, for the class you're writing, it's the caller or DI framework that controls which instance or implementation your class receives. This is an "inversion of control" compared to a self-contained class that maintains complete control of which classes or dependencies it uses.
As such, the class you're writing should be as general as possible when specifying its dependencies, which gives you flexibility about which implementations you can supply.
For example: If you need a sort algorithm, it would defeat the flexibility of dependency injection if you always asked specifically for a hypothetical MyBinarySortImpl; instead, you should make your request more general, such as injecting an interface like BinarySorter or Sorter (both also hypothetical). Your caller or dependency injection framework can still supply a MyBinarySortImpl, but by being as general as possible you also free your caller to supply a WellTestedNativeBinarySortImpl or a VeryFastRadixSortImpl. If your implementation needs to be a binary sort, you can specify that, and if it doesn't you can leave it general.
In your specific case, your #Provides method provides a binding of PrefsManager; the implementation happens to be a PrefsManagerImpl. However, the class that consumes PrefsManager is asserting that it doesn't need anything specific to PrefsManagerImpl, it can work when it only uses the interface as described through PrefsManager. That injecting class can now be tested using a FakePrefsManager or a mocking-framework-created mock(PrefsManager), or even a wrapper you could write like LoggingPrefsManager(PrefsManagerImpl(context)). By operating through interfaces rather than implementations, it keeps your options open.

Should I use #Singleton, object or both with Dagger2 and Kotlin?

I'm doing an app using Kotlin and Dagger2, trying to follow the MVVM pattern, but I'm in a dilemma, should I use #Singleton, object or both? And why? Let's say I have a RepositoryMovies class and I want to get the same instance every time, according to my research you can do this as follows:
#Singleton (Dagger2 way)
#Singleton
class RepositoryMovies {
TODO()
}
Object (Kotlin way)
object RepositoryMovies {
TODO()
}
Both
#Singleton
object RepositoryMovies {
TODO()
}
And don't get me started with singletons in Kotlin following the "Java-Way". I'd appreciate your help. Thanks so much.
Injecting an object doesn't make much sense, since in kotlin object is used to simulate java's utility classes, such as java's Arrays or Collections classes. One defining characteristic of such classes is that, they are not associated with any specific class in your project, they can be required and used anywhere.
On the other hand in most practical situations a repository will be associated with a specific class. for example you may only want to inject a UserRepository in a UserViewModel, because that is the only place where you need to access user's information.
As for the object and #Singleton, object is by definition a singleton, so marking it with #Singleton is redundant and doesn't accomplish anything until you make it injectable by means of a #Provides function. where you have to specify, how dagger can create instances of this class?
In your first example marking a class #Singleton doesn't do anything, unless it is injectable. as the docs state.
Singletons and Scoped Bindings
Annotate an #Provides method or injectable class with #Singleton. The graph will use a single instance of the value for
all of its clients.

Dagger2 one module for two different scopes

In my app i have an ApplicationScope which provides me with stuff like context and shared prefs.
2 sub components, LoggedInComponent and LoggedOutComponent.
Those 2 subcomponents have other subcomponents which are less relevant to the issue.
I have a NetworkModule which creates my retrofit instance.
Both subcomponents need the NetworkModule but the retrofit might change during the login because the base url and other settings might change.
I was wondering which approach it is better to take:
1. Give both LoggedIn and LoggedOut sub components and the NetworkModule the same scope so both sub components can use this module. Feels a bit hacky and wrong usage of scopes.
2. Put network module in the AppComponent with ApplicationScope. Also wrong usage of scope because network module is recreated so it cannot have same scope and also each recreation will cause the AppComponent and its subcomponents to be recreated.
What would you do? maybe there is a better solution?
You don't want LoggedInComponent and LoggedOutComponent to have differing network behavior, and you don't necessarily need network behavior to be consistent across the lifetime of LoggedInComponent or LoggedOutComponent, so it doesn't make sense for you to have them bind NetworkModule separately. I think it makes sense to make them available through AppComponent. Remember that not everything in AppComponent needs to have ApplicationScope: You can make unscoped bindings in AppComponent, which instructs Dagger to re-fetch or re-create the requested object every time.
Specifically, I would bind NetworkModule into a subcomponent of AppComponent, which you can recreate every time the NetworkModule configuration changes. Not only would this let you encapsulate some of the network details (see "subcomponents for encapsulation" in the Dagger User's Guide), but it would also let you take advantage of dependency injection throughout your network bindings if that's what you're looking for.
To ensure that you're getting the correct current NetworkComponent, you could create a NetworkManager that is singleton-bound (ApplicationScope). You can use that to hold the latest NetworkComponent.
#Module(subcomponents={NetworkComponent.class})
public abstract class ApplicationModule {
/** Unscoped. Fetch this fresh from NetworkComponentHolder each time. */
#Provides Retrofit provideRetrofit(NetworkManager manager) {
return manager.getNetworkComponent().getRetrofit();
}
}
#ApplicationScope public class NetworkManager {
private final Provider<NetworkComponent.Builder> builderProvider;
private NetworkComponent currentComponent;
#Inject public NetworkComponentHolder(
Provider<NetworkComponent.Builder> builderProvider) {
this.builderProvider = builderProvider;
currentComponent = builderProvider.get()
.withNetworkModule(getDefault())
.build();
}
public void updateSettings(String baseUrl) {
currentComponent = builderProvider.get()
.withNetworkModule(new NetworkModule(baseUrl))
.build();
}
public NetworkComponent getNetworkComponent() {
return currentComponent;
}
}
With this, most of your code in AppComponent, LoggedInComponent, and LoggedOutComponent can just inject a Retrofit (or Provider<Retrofit>) whenever they need to make a request. When a response comes back that tells you to update your base URL, you can inject a NetworkManager, call updateSettings, and suddenly new requests for Retrofit will return your new instance. (Note however that old instances to Retrofit may still stick around, but you'll have that problem any time you're changing a dependency belonging to an existing instance.)
p.s. If NetworkModule is lightweight enough, or has consistent-enough bindings, you might opt to put NetworkModule directly onto ApplicationComponent and simply have NetworkManager hold the current Retrofit instance etc. You'll have to make that judgment call based on the number of bindings you want to pass through as provideRetrofit does, compared to the number of bindings you'd want to encapsulate or hide away in a subcomponent.

What is the purpose of adding scope modifiers to #Components in Dagger2?

Say I have a class (or a #Provides method) annotated with #Singleton. This makes sense to me, whenever a dependency is provided from this class, the same instance will always be returned.
What I am trying to understand is why there is then a requirement for components that use that module to also be marked as #Singleton. The purpose of adding a scope to a component does not make sense to me. A component is an interface, that dagger uses to implement the actual injection.
If I try to compile my app with my dependency class marked as #Singleton, but do not have #Singleton marked on a component that injects this dependency, I get an error.
com.example.whatever.MyComponent (unscoped) cannot depend on scoped components
Adding #Singleton to the component makes this error go away, but I want to understand why. Can anyone help me understand this? Thanks!
Adding #Singleton on your component allows you to use #Singleton on your provider methods in your module you specify for your component. Scoped providers make it so that you can have only one instance from that given module without any additional magic beyond what Dagger2 generates for you.
#Singleton
#Component(module={BlahModule.class})
public interface SingletonComponent {
Blah blah();
}
#Module
public class BlahModule {
#Provides
#Singleton
public Blah blah() {
return new BlahImpl();
}
}
According to the Dagger 2 design doc, it is meant to make intention clear ("a declaration of intention") and to allow for better compile-time checking.
That declaration enables dagger to enforce the following constraints:
A given component may only have bindings (including scope annotations
on classes) that are unscoped or of the declared scope. I.e. a
component cannot represent two scopes. When no scope is listed,
bindings may only be unscoped.
A scoped component may only have one
scoped dependency. This is the mechanism that enforces that two
components don’t each declare their own scoped binding. E.g. Two
Singleton components that each have their own #Singleton Cache would
be broken.
The scope for a component must not appear in any of its
transitive dependencies. E.g.: SessionScoped -> RequestScoped ->
SessionScoped doesn’t make any sense and is a bug.
Singleton is
treated specially in that it cannot have any scoped dependencies.
Everyone expects Singleton to be the “root”.
This also makes some sense given the implementation of Dagger 2: Because Scopes are implemented via memoization and the user is responsible for instantiating a new Component instance for every new scope, then it makes sense that the Component has a lifetime (and set of provisions) to which the scope also applies.

Lazy Injection with Dagger 2 on 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.

Categories

Resources