将 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)扩展了 BaseObservable
而 LiveData
没有,则使用 Data Binding
的布局只会观察数据变化。我了解 LiveData
的主要目标之一是以编程方式观察和更新 UI 但对于简单更新,Data Binding
非常有用。
此问题已被报告 (GitHub and ),最初据说 1.0 版会有,现在据说此功能正在开发中。
为了同时使用 LiveData
和 Data 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
}
}
所以基本上我的 ObservableMutableLiveData
是 ObservableField
的副本,使用 LiveData
来存储模型,并且通过此实现,每次模型更新后布局都会更新。
问题是:
- 这是
LiveData
的错误实施吗?此包装器 "breaks" 是否具有 LiveData
的功能,例如生命周期感知?
- 在我的理解中,
LiveData
是新的 ObservableField
。这是正确的吗?
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.
对于那些像我一样遇到这个问题寻找例子的人,这里有一个:
在布局 .xml
中放置 LiveData
元素及其类型:
<layout>
<data>
<variable
name="myString"
type="android.arch.lifecycle.MutableLiveData<String>"/>
</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<String>
作为类型
对于 androidx 将是:
androidx.lifecycle.MutableLiveData
<layout>
<data>
<variable
name="myString"
type="androidx.lifecycle.MutableLiveData<String>"/>
</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
}
}
随着 Android 架构组件的稳定,我开始将我所有的基本 ViewModel
更新为 ViewModel
. In my understanding, the usage of LiveData
的新实现,建议保留 Model
class 因为它能更好地处理生命周期。
我喜欢使用 Data Binding
,因为它使 Java/Kotlin 端的代码更清晰,并且不需要 "watch" 值更改来更新 UI。但是,如果 Model
(或 ViewModel)扩展了 BaseObservable
而 LiveData
没有,则使用 Data Binding
的布局只会观察数据变化。我了解 LiveData
的主要目标之一是以编程方式观察和更新 UI 但对于简单更新,Data Binding
非常有用。
此问题已被报告 (GitHub and
为了同时使用 LiveData
和 Data 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
}
}
所以基本上我的 ObservableMutableLiveData
是 ObservableField
的副本,使用 LiveData
来存储模型,并且通过此实现,每次模型更新后布局都会更新。
问题是:
- 这是
LiveData
的错误实施吗?此包装器 "breaks" 是否具有LiveData
的功能,例如生命周期感知? - 在我的理解中,
LiveData
是新的ObservableField
。这是正确的吗?
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.
对于那些像我一样遇到这个问题寻找例子的人,这里有一个:
在布局 .xml
中放置 LiveData
元素及其类型:
<layout>
<data>
<variable
name="myString"
type="android.arch.lifecycle.MutableLiveData<String>"/>
</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<String>
作为类型
对于 androidx 将是:
androidx.lifecycle.MutableLiveData
<layout>
<data>
<variable
name="myString"
type="androidx.lifecycle.MutableLiveData<String>"/>
</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
}
}