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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With