将 LiveData 与数据绑定结合使用

Using LiveData with Data Binding

随着 Android 架构组件的稳定,我开始将我所有的基本 ViewModel 更新为 ViewModel. In my understanding, the usage of LiveData 的新实现,建议保留 Model class 因为它能更好地处理生命周期。

我喜欢使用 Data Binding,因为它使 Java/Kotlin 端的代码更清晰,并且不需要 "watch" 值更改来更新 UI。但是,如果 Model(或 ViewModel)扩展了 BaseObservableLiveData 没有,则使用 Data Binding 的布局只会观察数据变化。我了解 LiveData 的主要目标之一是以编程方式观察和更新 UI 但对于简单更新,Data Binding 非常有用。

此问题已被报告 (GitHub and ),最初据说 1.0 版会有,现在据说此功能正在开发中。

为了同时使用 LiveDataData Binding,我创建了一个非常简单的 class 实现,它扩展了 BaseObservable:

import android.arch.lifecycle.LiveData
import android.arch.lifecycle.MutableLiveData
import android.databinding.BaseObservable

class ObservableMutableLiveData<T>() : BaseObservable() {

    private var data: MutableLiveData<T> = MutableLiveData()

    constructor(data: T) : this() {
        this.data.value = data
    }

    public fun set(value: T) {
        if (value != data.value) {
            data.value = value
            notifyChange()
        }
    }

    public fun get(): T? {
        return data.value
    }

    public fun getObservable(): LiveData<T> {
        return data
    }
}

所以基本上我的 ObservableMutableLiveDataObservableField 的副本,使用 LiveData 来存储模型,并且通过此实现,每次模型更新后布局都会更新。

问题是:

Android Studio 3.1(目前在 Canary 6 中)将解决这个问题,因为 LiveData 可以用作 observable field:

Updates to Data Binding:

You can now use a LiveData object as an observable field in data binding expressions. The ViewDataBinding class now includes a new setLifecycle method that you need to use to use to observe LiveData objects.

来源:Android Studio 3.1 Canary 6 is now available

对于那些像我一样遇到这个问题寻找例子的人,这里有一个:

在布局 .xml 中放置 LiveData 元素及其类型:

<layout>
    <data>
        <variable
            name="myString"
            type="android.arch.lifecycle.MutableLiveData&lt;String&gt;"/>
    </data>

    ...

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text='@{myString}'
        ...
     />

    ...

</layout>

在您的代码中设置它的值和生命周期所有者:

MutableLiveData<String> myString = new MutableLiveData<>();

...

binding.setLifecycleOwner(this);
binding.setMyString(myString);

就是这样:)

请注意,LiveData 元素的默认值为 null,因此请分配初始值以确保您立即获得所需的效果,或使用 强制为空。

编辑: 如果使用 androidx.

,请使用 androidx.lifecycle.MutableLiveData&lt;String&gt; 作为类型

对于 androidx 将是:

androidx.lifecycle.MutableLiveData

<layout>
    <data>
        <variable
            name="myString"
            type="androidx.lifecycle.MutableLiveData&lt;String&gt;"/>
    </data>

    ...

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text='@{myString}'
        ...
     />

    ...

</layout>

对于 Kotlin:

  val myStr = MutableLiveData<String>()

...

 binding.apply {
            setLifecycleOwner(this)
            this.myString = myStr
        }

祝你好运! :)

接受的答案没有举例。所以这是我测试过的并且有效。

布局中:

<layout>
    <data>
        <variable
            name="viewmodel"
            type="com.abc.xyz.viewmodels.MyViewModel"/>
    </data>

    ...

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text='@{viewmodel.myString}'
        ...
     />

    ...

</layout>

片段中:

override fun onCreateView(inflater: LayoutInflater, 
         container: ViewGroup?, savedInstanceState: Bundle?): View? {
        val binding: FragmentAlbumBinding = DataBindingUtil.inflate(
            inflater, R.layout.fragment_album, container, false)
        binding.apply {
            fragment = this
            viewModel = albumViewModel
            lifecycleOwner = this
    }
}