I'm studying creation pattern(Singleton pattern) in android kotlin.
I have question about difference in making singleton object by companion object and object.
In some example, singletons are made like this.
class ABC {
companion object {
private var sInstance: ABC? = null
fun getInstance(): ABC {
if (sInstance == null) sInstance = ABC()
return sInstance ?: throw IllegalStateException("")
}
}
}
but with above method,
// a and b are not same object
val a = ABC()
val b = ABC.getInstance()
println(a == b) // false
but what I know, singleton in kotlin is just object.
So, my question is "Why, When use companion object to make singleton object"
getInstance() is just a "traditional" way of creating singletons. It is a common technique in e.g. Java, because contrary to Kotlin, Java doesn't have singletons provided by the language itself. For this reason you will see getInstance() from time to time in Kotlin as well. It may be the code ported from Java, it may be developed by a person who has more experience with Java, so they don't know there is a better alternative in Kotlin, etc.
Additionally, object is pretty much static. If we have more complicated logic for creating a singleton, it may be required to create it by some kind of factory (e.g. companion object).
So I would say, the rule of thumb is to use object as a default and only if this is not possible, create it manually. And in the latter case, it is more "Kotlin-ish" to use a property, not a getInstance() function.
Related
I am using Companion object in service to expose my LiveData to a fragment. Is this okay to use or will it cause me problems like memory leaks?
In my service:
companion object {
val timeLeftInSeconds = MutableLiveData<Long>(0)}
In my fragment:
LockoutService.timeLeftInSeconds.observe(viewLifecycleOwner, Observer {...})
No it's fine because companion object is kinda like static fields, but I highly recommend to use a repository instead because it will increase you code readability and makes it more robust. Something like
object AppRepository{
val timeLeftInSeconds = MutableLiveData<Long>(0)}
}
And in fragment
AppRepository.timeLeftInSeconds.observe(viewLifecycleOwner
No it's totally alright because companion objects are like static properties in java and are not bound to the class you define them in.
Also you can put it in the same file, outside of your service
LockoutService.kt
val timeLeftInSeconds = MutableLiveData<Long>(0)}
class LockoutService {...}
And access it without mentioning the service name
I have ever used Java to programming in android, but a few weeks ago I started to learn kotlin, when I use Java I tried to use object oriented approach and use the less possible static objects or instances, so when I see some materials in internet about some implementations of consume web services in kotlin I see something like this:
/*call of method from activity*/
val message = WebServiceTask.getWebservice(getString(R.string.url_service))
/*Class to do the call to webservice*/
class WebServiceTask {
companion object {
fun getWebService(url: String): WebServiceResponse {
val call =
RetrofitInstance.getRetrofit(url).create(ApiService::class.java).getList()
.execute()
val webServiceResponse = call.body() as WebServiceResponse
return user
}
}
}
/*Class to get Retrofit instance*/
class RetrofitInstance {
companion object{
fun getRetrofit(url: String): Retrofit {
return Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.build()
}
}
}
Like you see i use companion object in two classes and according to i read companion object is equivalent to static instance in java, so my question is:
is this code following object oriented programming?, this aproach is recommended?, in case that answer is no and which is the best implementation for this code in object oriented
Yes, companion object is Kotlin's equivalent of static members in Java. Everything that applies to static, applies to companion object as well.
The use of companion object depends on how it interacts with the state of class's object.
If you are using some methods which are totally Pure functions Or Some final values which you need to provide access to outside the class itself, in that case using companion object makes total sense.
It is recommended for the above conditions because it does not interfere with the state of the class's object.
So, for the given code snippet it is a valid use of companion object.
Observe that methods inside companion object do not interact with something which is not passed to them as parameters. Everything that you see is created/initialized or used inside the methods only, Just the result it gets out.
Note:
However, if your companion object members(values or functions) interfere with the state of the object, it will cause leaks, which will lead you to troubles you have never faced before.
Yes, it is equivalent to static. No, it is not recommended, as it leads to problems with mocking for testing, for example.
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.
Will there be any memory leaks if I access resources statically from My Application class like so:
class App : Application() {
companion object {
fun getResources(): Resources {
return this.getResources()
}
}
}
I was looking for a way to access my resources directly from my view models without passing a context object I just had to use AndroidViewModel instead of ViewModel from android arch components.
Thanks all.
Companion objects are not static, as the documentation describes:
Note that, even though the members of companion objects look like static members in other languages, at runtime those are still instance members of real objects, and can, for example, implement interfaces
You can't use companion object like this to get access to the App class. In your example, this refers to companion object itself, thus you're creating endless recursive call: this.getResources() just calls itself since this == App.Companion.
You cannot access App instance from its companion object, but you can access your companion instance from App class. That means, if you want to access your app context globally, you have to do smth like this:
class App {
override fun onCreate() {
super.onCreate()
appContext = this
}
companion object {
lateinit var appContext: Context
fun getResources(): Resources = appContext.resources
}
}
I've read a number of articles and stackoverflow posts regarding this question (mainly context instead of resources). A lot of people said it's OK because the Application class and the application context should always be alive throughout the life of the app, but some still discourage doing this sighting unknown possibilities (which made me doubtful - hence this post).
On the other hand, passing Context to every Object's function is quite daunting. In Java, one way to overcome this was to do something like UtilClass.getInstance(context) but you can't do that with Kotlin objects and I'm not too sure about implementing Kotlin Singletons with Arguments.
So, I have the following code:
class App : MultiDexApplication() {
override fun onCreate() {
super.onCreate()
_resources = resources
_context = applicationContext
//..other code
}
companion object {
val resources: Resources
get() = _resources!!
val context: Context
get() = _context!!
private var _resources: Resources? = null
private var _context: Context? = null
}
}
As you can see, I'm keeping a static reference to the application context and resources in a companion object when onCreate is called. With this, I'm able to (as examples):
call App.context in a util object that make API calls with Ion.
call App.resources in a util object that uses resource strings.
It's a convenience as compared to passing Context and/or Resources every time I call an object's method. Is this a safe solution? If not, are there any better alternatives?