使用Data Binding和LiveData

31
随着 Android 架构组件的稳定,我开始将所有基本的 ViewModel 更新到新的ViewModel实现。在我看来,建议使用LiveData来保存Model类,因为它可以更好地处理生命周期。
我喜欢使用Data Binding,因为它使得 Java/Kotlin 代码更清晰,并且不需要“观察”值的变化以更新 UI。但是,只有当Model(或 ViewModel)扩展 BaseObservable 时,使用Data Binding的布局才会监听数据的变化,而LiveData则不会。我理解 LiveData 的主要目标之一是被观察并通过编程方式更新 UI,但对于简单的更新,Data Binding非常有用。
这个问题已经被报告了(GitHubStack Overflow),最初说版本1.0会有这个功能,现在说这个功能正在开发中。
为了同时使用LiveDataData Binding,我创建了一个非常简单的类实现,它扩展了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
    }
}

基本上,我的 ObservableMutableLiveData 是 ObservableField 的一个副本,使用 LiveData 存储模型,在此实现中,布局在每次模型更新后都会更新。
问题是:
  • 这是一个糟糕的 LiveData 实现吗?这个包装器是否“破坏”了 LiveData 的功能,比如生命周期感知?
  • 据我理解,LiveData 是新的 ObservableField。这是正确的吗?

使用LiveData与数据绑定的正确方式现已在数据绑定文档中记录:使用LiveData通知UI有关数据更改 - Ben Butterworth
4个回答

35

如果你和我一样是在寻找示例而来到这个问题页面的,那么这里有一个示例:

在布局的.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;作为类型。


15

Android Studio 3.1(目前在Canary 6中)将解决此问题,因为LiveData可用作可观察字段

数据绑定更新:

您现在可以在数据绑定表达式中使用LiveData对象作为可观察字段。 ViewDataBinding类现在包括一个新的setLifecycle方法,您需要使用它来观察LiveData对象。

来源:Android Studio 3.1 Canary 6现已发布


你能提供一个如何做到这一点的例子吗? - kyurkchyan
7
请添加 binding.setLifecycleOwner(this);,具体操作请参考此链接:https://developer.android.com/topic/libraries/data-binding/architecture#java。 - Hun

1
对于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
        }

祝你好运!:)


1
接受的答案没有给出示例。这是一个我测试过并且有效的示例。
在布局中:
<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
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接