Android LiveData get()语法如何工作?

时间:2019-03-30 14:32:32

标签: android kotlin

我了解ViewModel中LiveData的need for creating getter and setter points,但我想了解get()语法在Android中的工作原理。

即:

val isRealtime: LiveData<Boolean>
    get() = _isRealtime
private val _isRealtime = MutableLiveData<Boolean>()

3 个答案:

答案 0 :(得分:2)

get()与Android不相关。

val isRealtime: LiveData<Boolean>
    get() = _isRealtime

在这里,get()覆盖了isRealtime属性的自动生成的Kotlin getter函数。因此,它不返回自己的值,而是返回_isRealtime的值。

我个人建议使用更简单的语法:

private val _isRealtime = MutableLiveData<Boolean>()
val isRealtime: LiveData<Boolean> = _isRealtime

这两种方法中的任何一个的目的都是保持可变性的私密性,因此此类消费者不会意外地更新MutableLiveData

答案 1 :(得分:1)

在Kotlin中,我们有多种将实时数据从ViewModel公开到视图的方法。

class MyViewModel: ViewModel() {

    // Solution 1 - make MutableLiveData public
    // This approach works, but this is a bad idea because
    // view can modify the LiveData values
    val liveDataA1 = MutableLiveData<State>()

    // Solution 2 - let's make LiveData public (expose it instead of MutableLiveData)
    // Now from view perspective this solution looks fine, bu we have a problem,
    // because we need MutableLiveData within ViewModel to put/post new values to
    // the stream (we can't post values to LiveData).
    val liveDataA2 = MutableLiveData<State>() as LiveData<State>

    // Let's capture our requirements:
    // 1. We need to expose (immutable) LiveData to the view,
    // so it cannot edit the data itself.
    // 2. We need to access MutableLiveData from ViewModel to put/post new values.
    // Now, let's consider few appropriate solutions

    // Solution 3
    // Let's name mutable live data using underscore prefix
    private val _liveData3 = MutableLiveData<State>()
    val liveData3 = _liveData3 as LiveData<State>

    // Solution 4
    // We can also perform casting by specifying type for a variable
    // (we can do it because MutableLiveData extends LiveData)
    private val _liveData4 = MutableLiveData<State>()
    val liveData4: LiveData<State> = _liveData4

    // Solution 5
    // Starting from Kotlin 1.4-M.2 we can delegate call to another property
    private val _liveData5 = MutableLiveData<State>()
    val liveData5 by this::_liveData5

    // Solution 6
    // These above solutions work quite well, but we could do even better by
    // defining custom asLiveData extension function.
    private val _liveData6 = MutableLiveData<State>()
    val liveData6 = _liveData6.asLiveData()

    fun <T> MutableLiveData<T>.asLiveData() = this as LiveData<T>
    // Amount of code is similar, but notice that this approach works much better
    // with code completion.

    // Solution 7 (IMO Best)
    // We can also use alternative naming convention - use "mutableLiveData"
    // as variable for mutable live data instead of using underscore prefix
    private val mutableLiveData7 = MutableLiveData<State>()
    val liveData7 = mutableLiveData7.asLiveData()

    // BTW
    // We could also expose getLiveData8() method, but liveData is a state not an action.

    // Solution 9
    // This does not create backing field for the property
    // (more optimised but still Solution 7 is easier to use)
    private val _liveData9 = MutableLiveData<State>()
    val liveData9 get() = _liveData9 as LiveData<State>
}

答案 2 :(得分:0)

我为此逻辑编写了一个util函数:

import android.arch.lifecycle.LiveData
import android.arch.lifecycle.MutableLiveData
import kotlin.reflect.KProperty

fun <T> immutable(data: MutableLiveData<T>): Immutable<T> {
    return Immutable(data)
}

class Immutable<T>(private val data: MutableLiveData<T>) {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): LiveData<T> {
        return data
    }
}

然后,您可以在任何ViewModel中使用以下方式:

private val _counter: MutableLiveData<Int> = MutableLiveData()    
val counter: LiveData<Int> by immutable(_counter)

或简而言之:

private val _counter = MutableLiveData<Int>()    
val counter by immutable(_counter)