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
Related
When I developed android app with Java I used EventBus , then I used java.util.observable to listen some var without getting a reference of a class/service.
For example, I could listen in ViewModel/Activity some var from a service without getting instance of that service.
I did it before I started using Clean Architecture, SOLID, MVVM etc.
Now I am using widely LiveData and ViewModel pattern, and Dependency Injection with Dagger2. So, every time I have a reference to listen a LiveData var.
I am wandering if exist in Kotlin a way to listen a var in one class from another class without getting an another class's reference?
This is not practical question, it's just curiosity
For listening to data from a variable just use LiveData.
wrap your variable in LiveData and use an observer to observe data changes to it.
Also if your variable is somewhere in a class which you don't want to create object of. Then you can simply wrap that variable in companion object like this.
class Test() {
companion object {
var testvariable = "Hello"
}
}
then simply call it like this "Test.testvariable"
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.
In kotlin we can use both of these approach lazy{} and getter()
lazy initializaiton:
internal val connector by lazy {
serviceConnector
}
getter():
internal val connector : ServiceConnector
get() = serviceConnector
When to use which approach and what actually does these two approach under the hood. Which one is best approach?
When you use the lazy delegate, the val is initialized only when you use it the first time. So, in your code, the first time you access connector, the code inside the lambda is run, and the result is assigned to the val.
get(), instead, is used to redefine what happens when you try to access the val.
I want to create a singleton in Kotlin so I made a companion object like this:
companion object {
val INSTANCE = MessagesManager()
}
There is something I want to do in its constructor so I wrote some code in the init function but it never runs if I don't use the Singleton.
I also tried to use the JVMField annotation but it doesn't work.
I want the init run would run immediately after startup.
init{} block will be called when the class is loaded.
So, you must access that class at least once after startup.
And, There is more comfortable way to make Singleton in Kotlin, like below.
object MessageManager {}
Like below?
val retro: Retro by lazy {
PilotApp.retro!!
}
class PilotApp : Application() {
companion object {
var retro: Retro? = null
}
override fun onCreate() {
retro = Retro(applicationContext)
super.onCreate()
}
}
Is this a good way of initialisation? Thanks in advance.
This is not following the rule of "Inversion of Control" and It is not a good idea.
The reason it is not a good idea is because whenever a class (like a ViewModel, Fragment or Activity or ...) wants to use the retro, they have to get the Retro object themselves by calling your first line (PilotApp.retro).
The alternative (called Dependency Injection/Inversion of Dependency) is that the Retro object is given to the class (again, the ViewModel or whatever) when it is initialized.
The reason why this is important is because with the second approach, you can make your classes that use the Retro, testable. You can give them RetroMock or TestRetro that does what you want (for example, mock an api to return an error).
Another note for your example, you don't need to make the retro nullable, you should make your var a lateinit and make it non-null.