Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/215.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 为什么';数据是否使用LiveData或Observable字段?_Android_Android Jetpack - Fatal编程技术网

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,因为它已经定义)
  • toyEntry
    是从上一步将这行xml连接到BindingAdapter的工具(它对应于您在注释
    @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
    ,因为它已经定义)
  • toyEntry
    是从上一步将这行xml连接到BindingAdapter的工具(它对应于您在注释
    @BindingAdapter(…)中设置的相同字符串)
现在,生成的代码知道您的绑定适配器,并在计算此数据绑定时调用其方法
setToyEntry
。您还可以删除行
android:text=“@={viewModel.toyBeingModified.toyName}”
,因为它不再使用

从那里开始设置双向数据绑定。这里还必须创建
@InverseBindingAdapter
,如下所述:

更多注释:根据您的gradle版本,您必须启用数据绑定,并确保设置了所有依赖项和gradle插件。
这里有更多信息:

事实上,当我们需要在更改后立即执行某些操作时,我们会使用LiveData或Observable字段,搜索栏就是一个很好的例子。但在这种情况下,我们不在乎用户何时更改所选玩具的属性(我没有看到UI,但我假设有一个保存按钮或类似的东西).换句话说,我们不想