Kotlin and jvm: object OR class instance? - android

object SampleObject{
fun getSampleText(): String = "123"
}
class SampleClass {
fun getSampleText(): String = "123"
}
There are no fields, methods only.
ActivityA starts ActivityB.
In ActivityB there is a call to SampleObject.getSampleText() and SampleClass().getSampleText(). Then ActivityB finishes.
What is the best practice? To use object or to use class instances?

If the function is pure (i.e. no side-effects), then code it at the top-level. No need to explicitly create a class/object in Kotlin.
The compiler will produce a class that contains your method as a static method, and therefore has the same lifecyle as all static methods.
An Object contains a static reference to a constructed version of itself, and the class has your function. Again, the class/method will exist for life of JVM

Related

How can a method from an interface can be called in the given project? (Whether I'm wrong?)

This is the project I'm trying to understand. I'm trying to understand what goes after what in this project. What confuses me, is that getFeatures() call in ViewModel. It seems that it calls an abstract function in the interface which is implemented in the file DefaultMapsRepository. I don't understand how it works. I thought that call should be of function from DefaultMapsRepository class where getFeatures() is implemented. So, as I understand, getFeatures() call in ViewModel calls the not implemented method from the interface and then that interface somehow finds the implementation of it and that override fun getFeatures() code runs its body. Correct me if I'm wrong. But If I create another implementation of getFeatures() how would that interface choose which implementation to use? I heard somewhere that interface of repository makes code easier to test but it's hard to understand how if I don't know how this all code works. I sometimes like to test how code works in the console to make code look simpler but I can't replicate the same situation because I'm not able to run the code if I add something to fun main() constructor. I think such structure of a project is used a lot and I want to understand it very well.
A different way of explaining it that might help. Suppose you have this interface and class.
interface Pet {
fun sayName()
}
class Dog(val name: String): Pet {
override fun sayName() {
println(name)
}
}
If some function asks for a Pet, you can pass it an instance of anything that implements the Pet interface.
fun sayPetName(pet: Pet) {
pet.sayName()
}
From the function's point of view, it doesn't have to know what class was passed to it. It just knows that whatever was passed to it is an instance of a Pet, and must therefore have a non-abstract sayName() function.
Even though the function sayName() is abstract inside the definition of the interface, it would be impossible to create an instance of a class where there is an abstract function. There's no such thing as an abstract function in an instance of a class. You can define abstract classes that have abstract functions, but you cannot create instances of them.
You could pass a Dog instance to this function since it qualifies as a Pet. When the function calls pet.sayName(), it is up to the instance of Dog to respond. The function itself doesn't have to know anything about what class type was passed to it.
In the same way, if you have an instance of a Pet that was passed to your constructor, your class can use the sayName() function on it. If you pass the class a Dog instance, even though the class is storing it in a property that is marked Pet and the class doesn't know it has a Dog, if it calls sayName() on it, the Dog instance will use its implementation of sayName().
class SomeClass(val pet: Pet) {
fun sayThePetName() {
pet.sayName()
}
}
If a Dog were passed to the constructor of the above class, it does not get "downgraded" into a Pet interface that has an abstract function. It's still a Dog instance even if that specific type is not exposed to the class in this scope. The code inside the class doesn't know or care that it's a Dog. It just knows it has a reference to some actual class instance that has the functions defined by the Pet interface.
An interface is just a contract. If CoolInterface has a property someValue: Int and a method doThing(): Boolean, then anything that implements that interface is guaranteed to have that property and that method.
The MapsViewModel class takes a MapsRepository parameter, and MapsRepository is just an interface with one function:
suspend fun getFeatures(): Resource<FeaturesResponse>
You can pass in anything that implements that interface, which DefaultMapsRepository does:
class DefaultMapsRepository #Inject constructor(
...
) : MapsRepository {
Since it implements that interface, it needs to implement that getFeatures function, which it does:
// override is the keyword that shows you're not just declaring a new function,
// it's implementing something abstract in a superclass/interface (or overriding
// an open function)
override suspend fun getFeatures(): Resource<FeaturesResponse> {
// bla bla
}
So you can pass in anything at all as your repository, so long as it implements MapsRepository, meaning you need some implementation of that getFeatures function. It doesn't "decide" a version to use, it calls it on whatever you pass in. So you can test it with whatever mock class or object you like
val mockRepo = object : MapsRepository {
override suspend fun getFeatures(): Resource<FeaturesResponse> {
return Resource.Error("oh snap")
}
}
val viewModel = MapsViewModel(mockRepo, whateverTheOtherThingIs)
// calls getFeatures() on the repo
viewModel.getFeatures()
If none of that makes any sense, you should read up on what interfaces and polymorphism are!

What object should I pass to a function that requires Void! in a parameter? (Kotlin)

I am using the contract ActivityResultContracts.TakePicturePreview() to capture a little image.
private val cameraLauncher =
registerForActivityResult(ActivityResultContracts.TakePicturePreview()) { bitmap ->
view?.findViewById<ImageView>(R.id.imageOutput)?.setImageBitmap(bitmap)
}
When I try to launch the Activity for Result, I realise that this contract requires a Void! object as a input. So that, The only way I can launch this activity is passing "null" as a parameter, what I think is not very beautiful.
cameraLauncher.launch(null)
I've tried passing "Nothing", "Unit" but the type mismatch.
What is the right way to do so?
The header of that function would be
public void launch(Void input)
As per the Java docs,
The Void class is an uninstantiable placeholder class to hold a reference to the Class object representing the Java keyword void
Because the Void class can not be instantiated, the only value you can pass to a method with a Void type parameter, is null.
The reason this is even required in the first place is because all the ActivityContracts inherit from the base abstract class ActivityResultContract<I, O> which expects two data types for input (I) and output(O). Since TakePicturePreview doesn't require any input, it uses Void? to just make up for that.
Now to answer,
What is the right way to do so?
Passing null is the right (and the only) way here.

Is it okay to use LiveData objects inside a service?

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

Do companion objects remain in memory for app's lifecycle

In Kotlin, you can create a singleton using a companion object:
class MyClass {
companion object {
fun doSomething() {
}
}
}
According to the Kotlin docs, it states:
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...
https://kotlinlang.org/docs/reference/object-declarations.html
Does this mean that after using a function in the companion object, the instance of the class (MyClass) remains in memory for the entire lifecycle of the app? Is there a way in Android Studio to check to see if this is the case?
instance of the class (MyClass) remains in memory for the entire lifecycle of the app?
Companion object in JVM
in kotlin
class MyClass {
companion object {
fun doSomething() {
}
}
}
MyClass(Kotlin) converted in JVM
public final class MyClass {
public static final MyClass.Companion Companion = new MyClass.Companion(null);
public static final class Companion {
public final void doSomething() {
}
private Companion() {
}
public Companion() {
this();
}
}
}
As above code, companion object is declared as Companion class in JVM, and it's created as static field inside MyClass class. Thus, isn't collected by gc. So, the memory of object(Companion) is remained during the ProcessLifecycle. static final object isn't released in normal case.
In conclusion, if referred to MyClass.Companion instance in application, that instance will not be garbage collected. (on general Classloaders).
*If not referred to MyClass.Companion instance in application, it may be removed by code shrinking feature.
Is there a way in Android Studio to check to see if this is the case?
You can see through android studio > profiler > Heap dump.
Reference
https://developer.android.com/topic/performance/memory-overview
https://developer.android.com/studio/build/shrink-code
As you seem to know and the above answer also makes clear that companion objects are translated to classes, and the class which declares them holds a static reference to the object of companion class, something as following:
public static final MyClass.Companion Companion = new MyClass.Companion(null);
Now the question
Do companion objects remain in memory for app's lifecycle
because the declaring class holds a static reference to companion class, the question reduces to the life time of static fields in jvm class and the answer lies in the JVM spec, but the spec is bit dry on the explanation so I am adding some snippets from the book Inside the Java Virtual Machine.
As in your example let say we have a class with nothing but single companion object.
First question is when an object of companion class will be created ? or
when static fields are initialized ?
relevant text from the book. (for context the book is talking about class loading procedure)
Initialization
The final step required to
ready a class or interface for its first active use is initialization,
the process of setting class variables to their proper initial values.
As used here, a "proper" initial value is the programmerís desired
starting value for a class variable. A proper initial value contrasts
with the default initial value given to class variables during
preparation. As described above, the virtual machine assigns default
values based only on each variableís type. Proper initial values, by
contrast, are based on some master plan known only to the programmer.
In Java code, a proper initial value is specified via a class variable
initializer or static initializer.
So we know that once MyClass is loaded and initialized, the object of companion class will be created.
but what would cause JVM to load MyClass ?
The Java Virtual Machine specification gives implementations
flexibility in the timing of class and interface loading and linking,
but strictly defines the timing of initialization. All implementations
must initialize each class and interface on its first active use. An
active use of a class is:
The invocation of a constructor on a new
instance of the class
The creation of an array that has the class as
its an element type
The invocation of a method declared by the class
(not inherited from a superclass)
4 The use or assignment of a field
declared by the class (not inherited from a superclass or
super interface), except for fields that are both static and final, and
are initialized by a compile-time constant expression
So as per 4th point when you do MyClass.foo() from kotlin or MyClass.Companion.foo() at this point MyClass will be loaded and ready. (Probably a lot early)
Please note that at this point no object of MyClass exist, that is we haven't used expression MyClass().
Does this mean static fields will remain in memory as long as the application is running ?
They can be garbage collected if the declaring type gets unloaded, in our case if JVM or ART (on android) unloads the MyClass then there is a possibility that companion object will be Garbage collected.
JVM Spec has following to say about class unloading
An implementation of the Java programming language may unload classes.
A class or interface may be unloaded if and only if its defining class
loader may be reclaimed by the garbage collector as discussed in
§12.6.
Classes and interfaces loaded by the bootstrap loader may not be
unloaded.
In practicality class unloading almost(I said almost) never happens, so yes companion objects will remain in memory for app's life cycle.

Prerequisite to create extension function in kotlin

I am learning Kotlin. As per I learnt, extension functions provides the ability to extend a class with new functionality without having to inherit from the class. I am creating extension function for okhttp3.RequestBody. But I am not able to get method in my activity.
Here is my extension function:
fun RequestBody.createPlainRequestBody(message: String): RequestBody = RequestBody.create(MediaType.parse("text/plain"), message)
while calling function as below I am getting unresolved function
RequestBody.createPlainRequestBody()
while I am creating extension function for toast I am getting perfect result as below:
fun Context.showToast(message: String) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
by calling:
this#MainActivity.showToast("Upload successfully")
Can any one guide for how to resolve this?
Extension functions can be applied to instances of a particular class, but you're trying to call it on a class, as if it were a static method. Moreover, your extension function expects an argument and you're not providing any.
What you need in your case is a simple function that creates a RequestBody as you're not acting on any particular instance of RequestBody.
Under the hood an extension function is simply a static method where the first argument is the receiver object and any other argument is shifted by one. Your showToast extension function is equivalent to the following Java snippet:
public static void showToast(Context receiver, String message) {
Toast.makeText(receiver, message, ...).show();
}
That's why you can call Kotlin extension functions from Java.
Unfortunately, you cannot do this in OkHttp version 3, however, you
will able to do this in OkHttp4 which is being rewritten completely in
Kotlin, so all the classes will be compatible with Koltin.
You have to extends to its companion object. (You need to make sure that class has a companion object associated with it)
fun RequestBody.Companion.createPlainRequestBody(message: String): RequestBody {
return RequestBody.create(MediaType.parse("text/plain"), message)
}
And after that, you will be able to call it directly from its class.
RequestBody.createPlainRequestBody("message")
Or
RequestBody.Companion.createPlainRequestBody("message")
A companion object is a normal object that associated with or belongs to the class it's similar to static object in Java. In Kotlin, it's called companion object.

Categories

Resources