get()和lazy之间的区别

时间:2019-08-06 14:36:09

标签: kotlin android-room android-livedata

有一个房间道,

@Dao
public abstract class AccountDao {
    @Query("SELECT * FROM Account LIMIT 0,1")
    public abstract Account readAccount();
}

下面的示例中get()by lazy之间有什么区别吗?

open val account: LiveData<Account>
        get() = accountDao.readAccount()
open val account: LiveData<Account> by lazy { accountDao.readAccount() }

2 个答案:

答案 0 :(得分:10)

不同之处在于函数主体(accountDao.readAccount())将执行多少次。

lazy委托将在第一次访问lambda时执行一次,并记住结果。如果再次调用,则返回该缓存的结果。

另一方面,定义getter(get())将每次执行函数主体,每次都返回一个新结果。

例如,假设我们有一个名为Foo的类,它同时具有一个getter和一个惰性值:

class Foo {
    val getterVal: String
        get() = System.nanoTime().toString()

    val lazyVal: String by lazy { System.nanoTime().toString() }
}

然后使用它:

fun main() {
    with(Foo()) {
        repeat(2) {
            println("Getter: $getterVal")
            println("Lazy:   $lazyVal")
        }
    }
}

对我来说,它打印:

Getter: 1288398235509938
Lazy:   1288398235835179
Getter: 1288398235900254
Lazy:   1288398235835179

我们可以看到getter每次都返回一个新计算的值,而lazy版本则返回相同的缓存值。

答案 1 :(得分:1)

除了托德的答案:

是的,LiveData个对象也有所不同。每次调用accountDao.readAccount()都会导致不同 LiveData对象。这确实很重要,尽管事实上,所有返回的LiveData都会在Account实体中的每次更改时得到更新。让我解释这些例子:

  • by lazy

正如Todd所提到的,lazy委托中的块将被执行一次,第一次访问account属性时,结果将被缓存并在每次下一次访问时返回。因此,在这种情况下,将创建一个LiveData<Account>对象。 Kotlin生成的字节码等效于Java:

public class Activity {

    private Lazy account$delegate

    public LiveData<Account> getAccount() {
        return account$delegate.getValue();
    }
}
  • get()

通过创建自定义account属性的getter并在内部调用accountDao.readAccount(),您在LiveData<Account>属性的每次访问中都会得到不同的account对象。再一次,在Java的Kotlin中为这种情况生成的字节码或多或少是这样的:

public class Activity {

    public LiveData<Account> getAccount() {
        return accountDao.readAccount();
    }
}

因此,您可以看到,使用惰性属性会为此属性生成一个后备字段,而使用自定义getter会为accountDao.readAccount()调用创建包装方法。

哪种方法取决于您的需要。我想说的是,如果您只需要获得LiveData一次,则应该使用get(),因为在这种情况下不需要后备字段。但是,如果您要在代码中的多个位置访问LiveData,也许更好的方法是使用by lazy并仅创建一次。