I am new to kotlin and I want to make an abstract/open class or interface, something that can be implemented by other classes. Let's call it Test. Now Test needs to have a HashSet (the docs say it requires less memory than a normal set) that every derived class will implement and fill with its own values.
interface Test {
val players: HashSet<String>
}
class Supa: Test {
override val players = hashSetOf<String>()
fun later() {
players.add("new player")
}
}
fun main() {
Supa().later()
println(Supa().players)
}
The above will output []. It seems that for some reason players doesn't get updated. After playing around in the kotlin playground I found out that if I print players from inside later() it will show the added element. Maybe it creates a new instance of player that exists in the scope of the function?? Could someone please show me how I can make an abstract hashSet that the derived class can override and fill with values that stay in the set?
The problem here is that you create two separate instances of Supa. You invoke later() on one of them and then print players of another one. Each Supa() creates a new instance.
You need to store Supa instance inside a variable and use it in both places:
val supa = Supa()
supa.later()
println(supa.players)
This isn't really specific to Kotlin. Your code would work the same in other languages as well.
Reasoning:
Hello guys. I'm building an evolution simulator as personal project. I have a few parameters set on textfields, such as the speed of the simulation and the number of "organisms". These are going to be accessed by multiple components of the application. Because i would also like to use validation on a few parameters, I set up a ViewModel like such:
class ParametersModel: ViewModel() {
// These properties would likely be DoubleProperty, but for simplicity lets pretend they are strings
val simulationSpeed = bind { SimpleStringProperty() }
val organismsGenerated = bind { SimpleStringProperty() }
}
... and then perform the validation tests on the textfields:
val model = ParametersModel()
textfield(model.simulationSpeed).required()
This works alright, but the issue with it is that I'm defining the model properties as a bind to an empty SimpleDoubleProperty, which is redundant since I'm never commiting this model (the program should always read changes as they are typed). At the same time, I cant define the model properties as simply:
class ParametersModel: ViewModel() {
val simulationSpeed = SimpleStringProperty()
val organismsGenerated = SimpleStringProperty()
}
Because I then get an error about the validation:
The addValidator extension can only be used on inputs that are already bound bidirectionally to a property in a Viewmodel. Use validator.addValidator() instead or make the property's bean field point to a ViewModel.
The other option I could take would be to make a class named something like GlobalProperties, which would keep my properties and also a ValidationContext. I could then add validators by using validationContext.addValidator and pass the textfields. But at this point I feel I'm just coding a ViewModel equivalent.
Question:
Is ViewModel the correct way of keeping "globally" accessed parameters set by textfields? If so, is there a way to not have to set the model properties as a bind of an empty one, since i dont ever need to commit anything?
Usually you would use a ViewModel with some sort of model. Then you can use the ViewModel to handle user input, which stores the current state of the user input, and the backing model will only be update when the ViewModel is committed, assuming validation passes (which seems at odds with your claim that you "dont ever need to commit anything").
Something like this:
class Parameters {
val simulationSpeedProperty = SimpleStringProperty(...)
var simulationSpeed by simulationSpeedProperty
val organismsGeneratedProperty = SimpleStringProperty(...)
var organismsGenerated by organismsGeneratedProperty
}
class ParametersModel(parameters: Parameters): ItemViewModel<Parameters>(parameters) {
val simulationSpeed = bind(Parameters::simulationSpeedProperty)
val organismsGenerated = bind(Parameters::organismsGeneratedProperty)
}
Then you can be sure that the Parameters backing the ParametersModel always has valid values in it (assuming of course it was initialized with valid values).
Im trying to get some data out of other ViewModels inside another ViewModel to make my code smaller, but im having a problem trying to implement what already worked on a fragment or in a activity, this is what i got:
class ObraConMediaViewModel(private val context: ViewModelStoreOwner,
private val id: Int): ViewModel(), LifecycleObserver {
var allObras: LiveData<ArrayList<ObraConMedia>>
private lateinit var viewModelobras: ViewModelObras
private lateinit var viewModelMediaObra: ViewModelMediaObra
val repositoryobras =ObrasRepository()
val repositoryMediaObra = MediaObraRepository()
val viewModelFactoryobras = ViewModelFactoryObras(repositoryobras)
val viewModelMediaObraFactory = ViewModelMedIaObraFactory(repositoryMediaObra)
init{
viewModelobras = ViewModelProvider(context, viewModelFactoryobras)
.get(ViewModelObras::class.java) // requireActivity() when called
viewModelMediaObra = ViewModelProvider(context, viewModelMediaObraFactory)
.get(ViewModelMediaObra::class.java)
viewModelobras.getObras(id)
viewModelobras.myResponse.observe(this , Observer { response ->
if (response.isSuccessful){
Log.d("Response", response.body()?.ans?.get(0)?.autor)
Log.d("Response", response.body()?.ans?.get(1)?.autor)
}else{
Log.d("Response", response.errorBody().toString())
}})
viewModelMediaObra.getMediaObra(Constantes.PRUEBA_ID)
viewModelMediaObra.myResponse.observe(this, Observer { response ->
if (response.isSuccessful){
Log.d("Response", response.body()?.ans?.get(0)?.filePath)
}
})
}}
I was having trouble with the Observer but extending the class to LifecycleObserver fixed it, i have no idea if this will even work but the only error that i have right now its the owner of the .observe(this,....), i dont seem to find a way to pass a lifecycleowner from the fragment to this viewmodel. All the variables i need to make this viewmodel work are inside those two responses. If this is a very bad way to do it please tell me. Thanks for reading.
Kindly note that above approach is not correct.
One should not create a instance of ViewModel inside another ViewModel.
There is a possibility that one ViewModel may get destroyed before another. This will lead to garbage reference and memory leaks.
I would recommend you to create the instance of both View Models in an Activity/Fragment and then call respective methods of ViewModel from Activity/Fragment.
Also, as you want to make your code smaller and concise, I highly recommend you Shared ViewModel.
This Shared ViewModel can be used by two fragments.
Please refer to this link
Having a room Dao as below,
#Dao
public abstract class AccountDao {
#Query("SELECT * FROM Account LIMIT 0,1")
public abstract Account readAccount();
}
is there any differences between get() and by lazy in the sample below?
open val account: LiveData<Account>
get() = accountDao.readAccount()
open val account: LiveData<Account> by lazy { accountDao.readAccount() }
The difference is in how many times the function body (accountDao.readAccount()) will be executed.
The lazy delegate will execute the lambda one single time the first time it is accessed and remember the result. If it is called again, that cached result is returned.
On the other hand, defining the getter (get()) will execute the function body every time, returning a new result every time.
For example, let's suppose we have a class called Foo with both a getter and a lazy value:
class Foo {
val getterVal: String
get() = System.nanoTime().toString()
val lazyVal: String by lazy { System.nanoTime().toString() }
}
And then use it:
fun main() {
with(Foo()) {
repeat(2) {
println("Getter: $getterVal")
println("Lazy: $lazyVal")
}
}
}
For me, this prints:
Getter: 1288398235509938
Lazy: 1288398235835179
Getter: 1288398235900254
Lazy: 1288398235835179
And we can see that the getter returns a newly calculated value each time, and the lazy version returns the same cached value.
In addition to Todd's answer:
Yes, there is a difference for LiveData objects as well. Every call of accountDao.readAccount() will result in a different LiveData object. And it does matter, despite the fact that all of the returned LiveData will get updated on every change in the Account entity. Let me explain on these examples:
by lazy
As Todd mentioned, the block inside the lazy delegate will be executed once, at the first time that the account property is accessed, the result will be cached and returned on every next access. So in this case a single one LiveData<Account> object is created. The bytecode generated by Kotlin to achieve this is equivalent to this in Java:
public class Activity {
private Lazy account$delegate
public LiveData<Account> getAccount() {
return account$delegate.getValue();
}
}
get()
By creating a custom account property's getter and calling accountDao.readAccount() inside, you will end up with different LiveData<Account> objects on every access of the account property. Once more, bytecode generated for this case in Kotlin in Java is more or less this:
public class Activity {
public LiveData<Account> getAccount() {
return accountDao.readAccount();
}
}
So you can see, using a lazy property results in generating a backing field for this property, while using a custom getter creates a wrapper method for the accountDao.readAccount() call.
It's up to your needs which approach you should use. I'd say that if you have to obtain the LiveData only once, you should go with get(), because a backing field is needless in that case. However if you're going to access the LiveData in multiple places in your code, maybe a better approach would be to use by lazy and create it just once.
In Kotlin, if you don't want to initialize a class property inside the constructor or in the top of the class body, you have basically these two options (from the language reference):
Lazy Initialization
lazy() is a function that takes a lambda and returns an instance of Lazy<T> which can serve as a delegate for implementing a lazy property: the first call to get() executes the lambda passed to lazy() and remembers the result, subsequent calls to get() simply return the remembered result.
Example
public class Hello {
val myLazyString: String by lazy { "Hello" }
}
So, the first call and the subsequential calls, wherever it is, to myLazyString will return Hello
Late Initialization
Normally, properties declared as having a non-null type must be initialized in the constructor. However, fairly often this is not convenient. For example, properties can be initialized through dependency injection, or in the setup method of a unit test. In this case, you cannot supply a non-null initializer in the constructor, but you still want to avoid null checks when referencing the property inside the body of a class.
To handle this case, you can mark the property with the lateinit modifier:
public class MyTest {
lateinit var subject: TestSubject
#SetUp fun setup() { subject = TestSubject() }
#Test fun test() { subject.method() }
}
The modifier can only be used on var properties declared inside the body of a class (not in the primary constructor), and only when the property does not have a custom getter or setter. The type of the property must be non-null, and it must not be a primitive type.
So, how to choose correctly between these two options, since both of them can solve the same problem?
Here are the significant differences between lateinit var and by lazy { ... } delegated property:
lazy { ... } delegate can only be used for val properties, whereas lateinit can only be applied to vars, because it can't be compiled to a final field, thus no immutability can be guaranteed;
lateinit var has a backing field which stores the value, and by lazy { ... } creates a delegate object in which the value is stored once calculated, stores the reference to the delegate instance in the class object and generates the getter for the property that works with the delegate instance. So if you need the backing field present in the class, use lateinit;
In addition to vals, lateinit cannot be used for nullable properties or Java primitive types (this is because of null used for uninitialized value);
lateinit var can be initialized from anywhere the object is seen from, e.g. from inside a framework code, and multiple initialization scenarios are possible for different objects of a single class. by lazy { ... }, in turn, defines the only initializer for the property, which can be altered only by overriding the property in a subclass. If you want your property to be initialized from outside in a way probably unknown beforehand, use lateinit.
Initialization by lazy { ... } is thread-safe by default and guarantees that the initializer is invoked at most once (but this can be altered by using another lazy overload). In the case of lateinit var, it's up to the user's code to initialize the property correctly in multi-threaded environments.
A Lazy instance can be saved, passed around and even used for multiple properties. On contrary, lateinit vars do not store any additional runtime state (only null in the field for uninitialized value).
If you hold a reference to an instance of Lazy, isInitialized() allows you to check whether it has already been initialized (and you can obtain such instance with reflection from a delegated property). To check whether a lateinit property has been initialized, you can use property::isInitialized since Kotlin 1.2.
A lambda passed to by lazy { ... } may capture references from the context where it is used into its closure.. It will then store the references and release them only once the property has been initialized. This may lead to object hierarchies, such as Android activities, not being released for too long (or ever, if the property remains accessible and is never accessed), so you should be careful about what you use inside the initializer lambda.
Also, there's another way not mentioned in the question: Delegates.notNull(), which is suitable for deferred initialization of non-null properties, including those of Java primitive types.
lateinit vs lazy
lateinit
i) Use it with mutable variable[var]
lateinit var name: String //Allowed
lateinit val name: String //Not Allowed
ii) Allowed with only non-nullable data types
lateinit var name: String //Allowed
lateinit var name: String? //Not Allowed
iii) It is a promise to compiler that the value will be initialized in future.
NOTE: If you try to access lateinit variable without initializing it then it throws UnInitializedPropertyAccessException.
lazy
i) Lazy initialization was designed to prevent unnecessary initialization of objects.
ii) Your property will not be initialized unless you use it.
iii) It is initialized only once. Next time when you use it, you get the value from cache memory.
iv) It is thread safe(It is initialized in the thread where it is used for the first time. Other threads use the same value stored in the cache).
v) The property can only be val.
vi) The property can be of any type (including primitives and nullables, which are not allowed with lateinit).
Very Short and concise Answer
lateinit: It initialize non-null properties lately
Unlike lazy initialization, lateinit allows the compiler to recognize that the value of the non-null property is not stored in the constructor stage to compile normally.
lazy Initialization
by lazy may be very useful when implementing read-only(val) properties that perform lazy-initialization in Kotlin.
by lazy { ... } performs its initializer where the defined property is first used, not its declaration.
Additionnally to hotkey's good answer, here is how I choose among the two in practice:
lateinit is for external initialisation: when you need external stuff to initialise your value by calling a method.
e.g. by calling:
private lateinit var value: MyClass
fun init(externalProperties: Any) {
value = somethingThatDependsOn(externalProperties)
}
While lazy is when it only uses dependencies internal to your object.
In addition to all of the great answers, there is a concept called lazy loading:
Lazy loading is a design pattern commonly used in computer programming to defer initialization of an object until the point at which it is needed.
Using it properly, you can reduce the loading time of your application. And Kotlin way of it's implementation is by lazy() which loads the needed value to your variable whenever it's needed.
But lateinit is used when you are sure a variable won't be null or empty and will be initialized before you use it -e.g. in onResume() method for android- and so you don't want to declare it as a nullable type.
Everything is correct above, but one of facts simple explanation LAZY----There are cases when you want to delay the creation of an instance of your object until its
first usage. This technique is known as lazy initialization or lazy instantiation. The main
purpose of lazy initialization is to boost performance and reduce your memory footprint. If
instantiating an instance of your type carries a large computational cost and the program
might end up not actually using it, you would want to delay or even avoid wasting CPU
cycles.
Diff btw lateinit and lazy
lateinit
Use only with mutable variable i.e. var and non-nullable data types
lateinit var name: String //Allowed with non-nullable
You are telling the compiler that the value will be initialized in future.
NOTE: If you try to access lateinit variable without initializing it then it throws UnInitializedPropertyAccessException.
lazy
Lazy initialization was designed to prevent unnecessary initialization of objects.
Your variable will not be initialized unless you use it.
It is initialized only once. Next time when you use it, you get the value from cache memory.
It is thread safe.
The variable can only be val and non-nullable.
Cheers :)
If you are using Spring container and you want to initialize non-nullable bean field, lateinit is better suited.
#Autowired
lateinit var myBean: MyBean
If you use an unchangable variable, then it is better to initialize with by lazy { ... } or val. In this case you can be sure that it will always be initialized when needed and at most 1 time.
If you want a non-null variable, that can change it's value, use lateinit var. In Android development you can later initialize it in such events like onCreate, onResume. Be aware, that if you call REST request and access this variable, it may lead to an exception UninitializedPropertyAccessException: lateinit property yourVariable has not been initialized, because the request can execute faster than that variable could initialize.