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.
Related
I'm currently migrating an app from anko-sqlite to room as anko has been discontinued a long time ago. In the process of doing so I introduced a repository layer and thought I would try to introduce dependency injection to get references to the repository instances in all my classes.
Prior to this I used a singleton instance that I just shoved into my application classes companion object and accessed that from everywhere.
I managed to inject my repositories into Fragments, Workmanager and Viewmodels. But I do now struggle a bit to understand how they forsaw we should handle this with arbitrary logic classes.
For instance my workmanager worker calls a class that instantiates a list of "jobs" and those need access to the repository. The worker itself actually bearly even does need access to the repositories as all the work is abstracted away from it.
How can I make something like this work
class Job(val someExtraArgINeed: Int) {
#Inject
lateinit var someRepository: SomeRepository // <= this should be injected when the job is instanciated with the constructor that already exists
}
For Activities and so forth we have special annotations #AndroidEntryPoint that makes this work. However, the documentation makes it unclear as to how we should get our instances from any other class that isn't an Android class. I understand that constructor injection is the recommended thing to use. But I do not think it would work here for me without an even more massive refactor required than this already would be.
If I understand your question correctly you can use hilt entry points like this
class CustomClass(applicationContext: Context) {
#EntryPoint
#InstallIn([/*hilt component that provide SomeRepository*/ApplicationComponent]::class)
interface SomeRepositoryEntryPoint {
fun provideSomeRepository(): SomeRepository
}
private val someRepository by lazy {
EntryPointAccessors.fromApplication(applicationContext, SomeRepositoryEntryPoint::class.java).provideSomeRepository()
}
fun doSomething() {
someRepository.doSomething()
}
}
I was going through one of my colleagues codebase. And I found this piece of code.
#Module
object SampleAppModule {
#Provides
#JvmStatic
#AppScope
fun provideAppDependency(context: Context): AppDependency = SampleAppDependency(context)
}
And this got me thinking, how's this different from this
#Module
class SampleAppModule {
#Provides
#AppScope
fun provideAppDependency(context: Context): AppDependency = SampleAppDependency(context)
}
I've seen the use of object in dagger modules recently, but I myself never used it because I didn't understand what it does. Would love to get some insights.
p.s. I tried changing the object to class, and it worked. Now I really don't know if there is any difference.
Using object to declare your Dagger modules would create only a single instance of it.
If your modules with #Provides are declared as class instead of object, then an additional object is generated on building the component. So using object, you get better performance.
Another way to do this would be using companion object. But that is not recommended:
Beyond that, don't use companion object for modules. Use object. In
that case the instance will be unused and its initialization code will
be removed by R8 and the methods will be truly static and can also be
inlined just like Java.
To define a singleton, should I use Kotlin object declaration or to make an ordinary Kotlin class and inject it using dagger? In my opinion the first option is definitely easier but there may be a reason to use dagger in this situation that I'm not aware of.
Option 1 (notice object keyword):
object SomeUtil {
// object state (properties)
fun someFunction(number: Long) {
// ...
}
}
Option 2 (notice class keyword):
class SomeUtil {
// object state (properties)
fun someFunction(number: Long) {
// ...
}
}
#Module
class AppModule {
#Provides
#Singleton
internal fun provideTheUtil() = SomeUtil()
}
class MainActivity : BaseActivity() {
#Inject internal lateinit var util: SomeUtil
}
UPDATE 2019-07-03
#Blackbelt said in comments that we should prefer option 2 for testability. But libraries like MockK can mock objects too. So do you still think option 2 is the preferred one?
You might want to reconsider the need of NumberFormatUtil being a singleton. It might be cheaper if you use #Reusable with Dagger or even a factory without any scope directly.
If NumberFormatUtil is fairly simple and only provides a few utility methods, no state and no need for mocking in tests, you could use an object implementation, maybe using #JvmStatic for Java-inter-operability. But then you could go for global utility (extension) functions as well:
package xyz
fun formatNumber(number: Long) {
// ...
}
fun Long.format() = formatNumber(this)
You should use option 2.
In software engineering, the singleton pattern is a software design
pattern that restricts the instantiation of a class to one "single"
instance. This is useful when exactly one object is needed to
coordinate actions across the system.
From: Singleton Pattern
So, a singleton is single instance in a scope. In case of Android, it is virtual machine instance running the app. In case you need custom scopes, you have to use option 2 only.
But, if you have only static methods inside the object you want to inject its better to keep them as global methods and even get rid of object. No need to inject anything. It is similar to a java class with only static methods (I mentioned this point as it is a usual way of creating Utility classes).
However, if the object also has some state. I would recommend going dagger way. The object way does not provide with dependency injection. It only creates a Singleton. Your purpose for using dagger is dependency injection.
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.
What is the difference between the #Singleton annotation on Dagger2 #Component annotated classes, and #Provides annotated methods in modules?
If I have one module in which all methods are annotated with a #Singleton annotation, and a component with the same annotation which includes that module, what is the purpose of this?
#Singleton
#Component(...)
public interface AppComponent {
// ...
}
And
#Provides #Singleton Context provideContext() { return context; }
Annotating the #Provides method (or the class with an #Inject constructor) tells Dagger to implement the actual scoping functionality whereas annotating the component (which is necessary) doesn't have any functionality, but tells Dagger "I allow this component to contain bindings of this scope". Note that you can still have unscoped bindings in a scoped component, but not the other way around.
It's well within the use of a Java annotation to provide documentation to reader, which is what you're probably seeing in your first example. It's useful there so the reader can know the intended use of the class/interface without having to know the mechanism by which its instance is created or managed.