What is the purpose of #Singleton on a function (Hilt) - android

In Android Hilt, you can apply the #Singleton annotation to a function like this:
#Module
#InstallIn(SingletonComponent::class)
object SomeModule {
#Singleton
#Provides
fun provideSomething(): String {
return "Hi there"
}
}
I don't understand what the purpose of using a singleton on a function accomplishes. A class that has the #Singleton means that an instance of the class only exists once. But you cannot create instances of functions, so I don't see the point.

#Singleton is called Scope and by default, all bindings in Hilt are unscoped. This means that each time your app requests the binding, Hilt creates a new instance of the needed type. For example in your case each time you request a String a new string is going to be created.
But when you add #Singleton annotation you said that the scope of this instance is singleton so it's going to provide the same instance each time you request a String.
Unlike SingletonComponent which is a component, it decide where you can use that module, so if you change it to ViewModelComponent for example you will be able to use that module only from ViewModel and it's lifecycle is going to be related to the ViewModel lifecycle.
You can take a look here for more information: https://developer.android.com/training/dependency-injection/hilt-android#generated-components
Take a look at this example:
instead of just providing a static string try to provide some random number:
#Provides
fun provideString(): String {
return (1..100).random().toString()
}
Without #Singleton when you inject String in different classes in your App you will get different results because each time hilt is going to run the code inside provideString function so it's going to return a new instance of String ( that's what I mean by providing a new instance ).
Now add #Singleton:
#Singleton
#Provides
fun provideString(): String {
return (1..100).random().toString()
}
You will notice that the provided String is the same across your app so provideString is called once and the result is saved so hilt is returning that saved instance of String every time.

Functions can be singletons just like classes , It will assure only one instance will be created .
Normally multiple calls of same function will be stacked , and performed one by one , while in a singleton function , last call will overwrite the previous one .so if you called it 10 times in a loop , no instances of the calls will be stacked in the memory.

Related

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.

Trying to solve a dependency cycle using dagger

dagger-android 2.16
I have a dependency cycle error in my Dagger module. I think I know what the problem is but not sure how to solve it.
This is the error message:
Found a dependency cycle:
public interface LoginFragmentSubcomponent extends AndroidInjector<LoginFragment> {
presentation.login.request.LoginRequest is injected at
mobileui.login.di.LoginActivityModule.provideLoginResponseListener(…, loginRequest)
presentation.login.response.LoginResponseListener is injected at
mobileui.login.di.LoginActivityModule.provideLoginRequest(…, loginPresenter)
presentation.login.request.LoginRequest is injected at
mobileui.login.di.LoginActivityModule.provideLoginPresenter(…, loginRequest)
mobileui.login.LoginPresenter is injected at
mobileui.login.LoginFragment.loginPresenter
This is the module below where I am getting the error
#Module
class LoginActivityModule {
#Reusable
#Provides
fun provideLoginPresenter(loginRequest: LoginRequest): LoginPresenter {
return LoginPresenterImp(loginRequest)
}
#Reusable
#Provides
fun provideLoginResponseListener(loginRequest: LoginRequest): LoginResponseListener {
LoginPresenterImp(loginRequest)
}
#Reusable
#Provides
fun provideLoginRequest(loginUser: LoginUser,
loginPresenter: LoginResponseListener): LoginRequest {
return LoginRequestImp(loginUser, loginPresenter)
}
}
My LoginPresenterImp implements the LoginResponseListener and I want to pass that to the LoginRequestImp class so I can use it as a callback.
class LoginPresenterImp(private val loginRequest: LoginRequest) :
BasePresenterImp<LoginView>(),
LoginPresenter,
LoginResponseListener {
}
And the loginResponseListener gets passed here:
class LoginRequestImp(
private val loginUser: LoginUser,
private val loginResponseListener: LoginResponseListener)
: LoginRequest {
}
Many thanks in advance,
As Ayush described in the comments:
You need LoginResponseListener to create LoginRequest and you need LoginRequest to create LoginResponseListener. So, you are getting the error.
When you are creating LoginRequest in LoginRequestImp(loginUser, loginPresenter), loginPresenter is a parameter to the constructor of type LoginResponseListener. You should try to eliminate this dependency. May be you can set the listener later from the presenter
In your reply between those comments:
LoginRequest has been created in provideLoginRequest
But this is what's happening:
Your LoginFragment tries to inject LoginPresenter.
Before you inject LoginPresenter you need to create a LoginRequest.
Before you create a LoginRequest you need a LoginUser and a LoginRequestListener.
Before you create a LoginRequestListener (which you've implemented as a LoginPresenterImpl), you need a LoginRequest.
You're in the middle of creating a LoginRequest, so Dagger gives up and correctly reports a circular reference.
To reiterate: Even though you've set up the bindings using interfaces correctly, Dagger can't create any of them because to call either constructor it has to create the other. This isn't a problem with Dagger: If class A's constructor takes an instance of B, and class B's constructor takes an instance of A, you couldn't construct either of them manually either while respecting their constructor parameters.
As Ayush suggested, don't have LoginRequest inject a LoginResponseListener. Instead, create a method like setLoginResponseListener, which LoginPresenterImp can call. I recommend this approach as well, in part because #Reusable has weaker semantics than you want: You want to be absolutely sure that the LoginPresenterImp instance that acts as your LoginPresenter is the same instance that acts as LoginResponseListener.
As an alternative, you can inject Provider<LoginPresenter> instead of LoginResponseListener, and change LoginRequestImp to accept a Provider as well. (You could also inject a Provider<LoginResponseListener>, but if you want that LoginResponseListener to be the same one as your LoginPresenter instance, you shouldn't call the LoginPresenterImp constructor explicitly. You'd want to switch to #Binds ideally, or at least have your #Provides method inject LoginPresenter instead.) You're allowed to inject a Provider, because a Provider<T> is automatically bound for every class <T> that Dagger knows how to provide, and it solves your problem because Dagger can pass a Provider<T> without trying to create the T. This will technically appear to work even if you leave your bindings as #Reusable, but in a multithreaded environment #Reusable isn't going to guarantee that you always receive the same instance for LoginRequestListener as your LoginPresenter, or that you'll receive a new LoginPresenter for every LoginFragment. If you want to guarantee that, you can look into custom scopes.

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.

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.

Dagger 2 Custom Scope for each Fragment (or Activity etc...)

I've looked at a couple different articles which seem to suggest two different ways of doing custom scoping in Dagger 2:
MVP Presenters that Survive Configuration Changes Part-2 (Github repo):
Uses unique custom scopes for each fragment, e.g. #Hello1Scope and #Hello2Scope for Hello1Fragment and Hello2Fragment respectively
Tasting Dagger 2 on Android:
Uses a single custom scope for all fragments, e.g. #PerFragment.
From what I understand, it seems that, as in method 2, it should be okay to have a single scope defined that can be used for all fragments (i.e., #PerFragment). In fact (please correct me if I'm wrong), it seems like the name of the custom scope is irrelevant, and it's only where the subcomponent is created (i.e. in Application, Activity, or Fragment) that matters.
Is there any use case for defining a unique scope for each fragment such as in case 1?
After reading the answer by #vaughandroid, and What determines the lifecycle of a component (object graph) in Dagger 2? I think I understand custom scopes well enough to answer my own question.
First, here are a couple rules when dealing with components, modules, and scoping annotations in dagger2.
A Component must have a (single) scope annotation (e.g. #Singleton or #CustomScope).
A Module does not have a scope annotation.
A Module Method may have a (single) scope that matches its Component or no scope, where:
Scoped: means a single instance is created for each instance of the component.
Unscoped: mean a new instance is created with each inject() or provider call
NOTE: Dagger2 reserves #Singleton for the root Component (and it's modules) only. Subcomponents must use a custom scope, but the functionality of that scope is exactly the same as #Singleton.
Now, to answer the question: I would say create a new named scope for each conceptually different scope. For example, create a #PerActivity, #PerFragment, or #PerView annotation that indicates where the component should be instantiated, and thus indicating its lifetime.
Note: this is a compromise between two extremes. Consider the case of a root component and n subcomponents you will need:
at least 2 annotations (#Singleton and #SubSingleton), and
at most n+1 annotations (#Singleton, #SubSingleton1, ... #SubSingletonN).
Example:
Application:
/** AppComponent.java **/
#Singleton
#Component( modules = AppModule.class )
public interface AppComponent{
void inject(MainActivity mainActivity);
}
/** AppModule.java **/
#Module
public class AppModule{
private App app;
public AppModule(App app){
this.app = app;
}
// For singleton objects, annotate with same scope as component, i.e. #Singleton
#Provides #Singleton public App provideApp() { return app; }
#Provides #Singleton public EventBus provideBus() { return EventBus.getDefault(); }
}
Fragment:
/** Fragment1Component.java **/
#PerFragment
#Component( modules = {Fragment1Module.class}, dependencies = {AppComponent.class} )
public interface Fragment1Component {
void inject(Fragment1 fragment1);
}
/** Fragment1Module.java **/
#Module
public class Fragment1Module {
// For singleton objects, annotate with same scope as component, i.e. #PerFragment
#Provides #PerFragment public Fragment1Presenter providePresenter(){
return new Fragment1Presenter();
}
}
/** PerFragment.java **/
#Scope
#Retention(RetentionPolicy.RUNTIME)
public #interface PerFragment {}
Your understanding is correct. The named scopes allow you to communicate intention, but they all work the same way.
For scoped provider methods, each Component instance will create 1 instance of the provided object.
For unscoped provider methods, each Component instance will create a new instance of the provided object whenever it needs to inject it.
The lifetime of the Component instance is important though. 2 different instances of the same component will provide different object instances, even scoped ones.
Scope names should indicate the lifetime of the provided object (which matches that of the Component instance) so #PerFragment makes much more sense to me.
From a quick look at the "MVP Presenters..." tutorial, it's not clear to me exactly what the author's intention is with having separate scopes. Since the names are just throwaway ones, I wouldn't read too much into it.

Categories

Resources