Android 为什么';数据是否使用LiveData或Observable字段?
在我看来,单向或双向数据必应使用Android 为什么';数据是否使用LiveData或Observable字段?,android,android-jetpack,Android,Android Jetpack,在我看来,单向或双向数据必应使用LiveData或可观察字段 以下代码来自该项目 控件的属性android:text=“@={viewModel.toybeingmedited.toyName}”通过双向数据绑定到viewModel.toybeingmedited.toyName 我很奇怪为什么viewModel.toyBeingModified既不是LiveData也不是可观察字段,你能告诉我吗 fragment\u add\u toy.xml <layout xmlns:android
LiveData
或可观察字段
以下代码来自该项目
控件的属性android:text=“@={viewModel.toybeingmedited.toyName}”
通过双向数据绑定到viewModel.toybeingmedited.toyName
我很奇怪为什么viewModel.toyBeingModified
既不是LiveData
也不是可观察字段
,你能告诉我吗
fragment\u add\u toy.xml
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data class="AddToyBinding">
<variable
name="viewModel"
type="com.enpassion.twowaydatabindingkotlin.viewmodel.AddToyViewModel" />
<import type="com.enpassion.twowaydatabindingkotlin.utils.BindingUtils"/>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="@dimen/margin_standard">
<androidx.cardview.widget.CardView
android:id="@+id/cardEditText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/margin_standard"
app:cardBackgroundColor="@color/skin_rose"
app:cardCornerRadius="@dimen/card_corner_radius"
app:cardElevation="@dimen/card_elevation"
app:contentPadding="@dimen/padding_standard"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
...
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/toyNameLayout"
style="@style/Widget.Enpassio.TextInputLayout"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:hint="@string/toy_name"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="@+id/guidelineET"
app:layout_constraintTop_toTopOf="parent"
tools:layout_editor_absoluteY="418dp">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/toyNameEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textCapWords"
android:text="@={viewModel.toyBeingModified.toyName}"/>
</com.google.android.material.textfield.TextInputLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
...
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
ToyEntry.kt
class AddToyViewModel(private val mRepo: ToyRepository, private val chosenToy: ToyEntry?) : ViewModel() {
val toyBeingModified: ToyEntry
private var mIsEdit: Boolean = false
init {
if (chosenToy != null) {
//This is edit case
toyBeingModified = chosenToy.copy()
mIsEdit = true
} else {
/*This is for adding a new toy. We initialize a ToyEntry with default or null values
This is because two-way databinding in the AddToyFragment is designed to
register changes automatically, but it will need a toy object to register those changes.*/
toyBeingModified = emptyToy
mIsEdit = false
}
}
private fun insertToy(toy: ToyEntry) {
mRepo.insertToy(toy)
}
...
}
data class ToyEntry(
var toyName: String,
var categories: Map<String, Boolean>,
var gender: Gender = Gender.UNISEX,
var procurementType: ProcurementType? = null,
@PrimaryKey(autoGenerate = true) val toyId: Int = 0
): Parcelable{
/*This function is needed for a healthy comparison of two items,
particularly for detecting changes in the contents of the map.
Native copy method of the data class assign a map with same reference
to the copied item, so equals() method cannot detect changes in the content.*/
fun copy() : ToyEntry{
val newCategories = mutableMapOf<String, Boolean>()
newCategories.putAll(categories)
return ToyEntry(toyName, newCategories, gender, procurementType, toyId)
}
}
数据类ToyEntry(
var toyName:String,
变量类别:映射,
变量性别:性别=性别。男女通用,
var procurementType:procurementType?=null,
@PrimaryKey(autoGenerate=true)val toyId:Int=0
):可包裹{
/*此功能用于两个项目的健康比较,
特别是用于检测地图内容的变化。
数据类的本机复制方法指定具有相同引用的映射
对于复制的项,因此equals()方法无法检测内容中的更改*/
有趣的副本():ToyEntry{
val newCategories=mutableMapOf()
newCategories.putAll(类别)
返回到Entry(toyName、新类别、性别、procurementType、toyId)
}
}
我建议先从单向数据绑定开始,一旦成功,就扩展到双向数据绑定。你现在做错了以下几点:
android:text="@={viewModel.toyBeingModified.toyName}"
这行代码意味着您将ToyEntry
对象传递给TextView的setText()
方法。这意味着TextView
需要一个带有签名的方法:setText(条目:ToyEntry)
当然,这种方法还不存在。因此,要使此数据绑定工作,您必须通过创建BindingAdapter
,自己定义此方法:
@BindingAdapter("toyEntry")
fun setToyEntry(textView: TextView, toyEntry: ToyEntry) {
// in here you define what to do with the textView. For example:
textView.text = toyEntry.toyName
}
- 您可以在任何文件中创建此BindingAdapter,而无需将其放入类中
- 你可以给这个方法取任何你想要的名字
- 此方法的第一个参数是要将toyEntry绑定到的xml中的视图类型
- 此方法的第二个参数是通过
在xml中设置的对象@{…}
binding:toyEntry=“@{viewModel.toybeingmedited.toyName}”
- AndroidStudio可以自动对
命名空间进行封装。您可以将其命名为任何您想要的名称(但不能命名为android,因为它已经定义)绑定
是从上一步将这行xml连接到BindingAdapter的工具(它对应于您在注释toyEntry
@BindingAdapter(…)中设置的相同字符串)
setToyEntry
。您还可以删除行android:text=“@={viewModel.toyBeingModified.toyName}”
,因为它不再使用
从那里开始设置双向数据绑定。这里还必须创建@InverseBindingAdapter
,如下所述:
更多注释:根据您的gradle版本,您必须启用数据绑定,并确保设置了所有依赖项和gradle插件。
这里有更多信息:我建议先从单向数据绑定开始,一旦成功,就将其扩展到双向数据绑定。您现在的错误是:
android:text="@={viewModel.toyBeingModified.toyName}"
这行代码意味着您将ToyEntry
对象传递给TextView的setText()
方法。这意味着TextView
需要有一个带有签名的方法:setText(条目:ToyEntry)
当然,此方法还不存在。因此,要使此数据绑定工作,您必须通过创建BindingAdapter
,自己定义此方法:
@BindingAdapter("toyEntry")
fun setToyEntry(textView: TextView, toyEntry: ToyEntry) {
// in here you define what to do with the textView. For example:
textView.text = toyEntry.toyName
}
- 您可以在任何文件中创建此BindingAdapter,而无需将其放入类中
- 你可以给这个方法取任何你想要的名字
- 此方法的第一个参数是要将toyEntry绑定到的xml中的视图类型
- 此方法的第二个参数是通过
在xml中设置的对象@{…}
binding:toyEntry=“@{viewModel.toybeingmedited.toyName}”
- AndroidStudio可以自动对
命名空间进行封装。您可以随意命名它(但不能绑定
,因为它已经定义)android
是从上一步将这行xml连接到BindingAdapter的工具(它对应于您在注释toyEntry
@BindingAdapter(…)中设置的相同字符串)
setToyEntry
。您还可以删除行android:text=“@={viewModel.toyBeingModified.toyName}”
,因为它不再使用
从那里开始设置双向数据绑定。这里还必须创建@InverseBindingAdapter
,如下所述:
更多注释:根据您的gradle版本,您必须启用数据绑定,并确保设置了所有依赖项和gradle插件。
这里有更多信息:事实上,当我们需要在更改后立即执行某些操作时,我们会使用LiveData或Observable字段,搜索栏就是一个很好的例子。但在这种情况下,我们不在乎用户何时更改所选玩具的属性(我没有看到UI,但我假设有一个保存按钮或类似的东西).换句话说,我们不想