【问题标题】:Difference between get() and by lazyget() 和 bylazy 的区别
【发布时间】:2019-08-06 14:36:09
【问题描述】:

有房道如下,

@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() }

【问题讨论】:

    标签: kotlin android-room android-livedata


    【解决方案1】:

    区别在于函数体 (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版本返回的缓存值相同。

    【讨论】:

    • 我猜既然是LiveData,单次执行accountDao.readAccount()就足够了?
    • 这取决于您是否需要每次调用的更新值或缓存返回
    【解决方案2】:

    除了托德的回答:

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

    • by lazy

    正如 Todd 提到的,lazy 委托中的块将执行一次,在第一次访问 account 属性时,结果将被缓存并在每次下一次访问时返回。因此,在这种情况下,会创建一个 LiveData&lt;Account&gt; 对象。 Kotlin 为实现这一点而生成的字节码等价于 Java 中的 this:

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

    通过创建自定义account 属性的getter 并在内部调用accountDao.readAccount(),您将在每次访问account 属性时得到不同的LiveData&lt;Account&gt; 对象。再一次,在 Java 中的 Kotlin 中为此案例生成的字节码或多或少是这样的:

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-02-20
      • 1970-01-01
      • 1970-01-01
      • 2023-01-18
      • 1970-01-01
      • 2016-02-10
      • 2012-12-24
      • 1970-01-01
      相关资源
      最近更新 更多