当前位置: 首页 > 知识库问答 >
问题:

使用数据绑定时出现的问题:val vs var和invalidateAll()的使用

欧阳何平
2023-03-14

这实际上是两个问题。

  1. 我注意到,如果在Person数据类中,我将name参数设置为val,而不是var,那么数据绑定将不起作用。代码将中断,出现以下错误:
error: cannot find symbol
import com.example.android.aboutme.databinding.ActivityMainBindingImpl;
                                              ^
  symbol:   class ActivityMainBindingImpl
  location: package com.example.android.aboutme.databinding

为什么会这样?

主要活动:

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding
    val person = Person("Bob")

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
        binding.person = person

        binding.apply {
            btnDone.setOnClickListener { doneClick(it) }
        }
    }

    private fun doneClick(view: View) {
        binding.apply {
            person?.nickname = etNickname.text.toString()
            invalidateAll()
            etNickname.visibility = View.GONE
            tvNickname.visibility = View.VISIBLE
            btnDone.visibility = View.GONE
        }

        hideKeybord(view)
    }

    private fun hideKeybord(view: View) {
        val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
        imm.hideSoftInputFromWindow(view.windowToken, 0)
    }
}

人员:

class Person(var name: String, var nickname: String? = null)

activity\u main。xml:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>

        <variable
            name="person"
            type="com.example.android.aboutme.Person" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:paddingStart="@dimen/padding"
        android:paddingEnd="@dimen/padding">

        <TextView
            android:id="@+id/tv_name"
            style="@style/NameStyle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@={person.name}"
            android:textAlignment="center" />

        <EditText
            android:id="@+id/et_nickname"
            style="@style/NameStyle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:ems="10"
            android:hint="@string/what_is_your_nickname"
            android:inputType="textPersonName"
            android:textAlignment="center" />

        <Button
            android:id="@+id/btn_done"
            style="@style/Widget.AppCompat.Button.Colored"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="@dimen/layout_margin"
            android:fontFamily="@font/roboto"
            android:text="@string/done" />

        <TextView
            android:id="@+id/tv_nickname"
            style="@style/NameStyle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@={person.nickname}"
            android:textAlignment="center"
            android:visibility="gone" />

        <ImageView
            android:id="@+id/star_image"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="@dimen/layout_margin"
            android:contentDescription="@string/yellow_star"
            app:srcCompat="@android:drawable/btn_star_big_on" />

        <ScrollView
            android:id="@+id/bio_scroll"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginTop="@dimen/layout_margin">

            <TextView
                android:id="@+id/bio_text"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:lineSpacingMultiplier="@dimen/line_spacing_multiplier"
                android:text="@string/bio"
                android:textAppearance="@style/NameStyle" />

        </ScrollView>
    </LinearLayout>
</layout>

共有2个答案

高建本
2023-03-14
  1. Val=可变Var=可变

静态编程语言中的Val和Var

苏昊英
2023-03-14

问题1:

我注意到,如果在Person数据类中我将name参数设置为val而不是var,则数据绑定不起作用。

为什么会发生?

因为您正在使用双向数据绑定。

在您的布局中,您有以下内容:

<TextView
    android:id="@+id/tv_name"
    style="@style/NameStyle"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="@={person.name}"
    android:textAlignment="center" />

android:text=“@={person.name}”中的@=告诉databinding“我想将文本视图的文本设置为该人的名称值,并且我想在文本视图文本更改时更新该人的名称”。

使用@=数据绑定时,将为正在分配的属性查找setter。在本例中,它正在查找Person类上的name属性的setter。在Kotlin中,这意味着拥有一个名为name的属性,即var。

如果您不打算在TextView更改时更新该人的name属性(我假设您不会,您通常会使用EditText来执行此操作),然后将该行更改为仅@android: text="@{person.name}")。然后您可以将name设为val,因为您只是从其中读取数据。

问题二:

为什么我需要在doneClick()中调用invalidateAll()?

你真的不。。。

留档说它“使所有绑定表达式无效并请求新的重新绑定以刷新UI”。数据绑定的目的不是为了连接数据和视图,以便更新数据立即更新视图吗?

是的,但是:数据绑定不是魔法。如果UI要更新,则必须告诉它这样做,而更改数据并不会神奇地告诉数据绑定它必须更新。必须告诉数据绑定:a)是时候更新了,b)需要更新什么。

因此,您现在使用的是散弹枪方法。您更新了一个昵称字段,然后对数据绑定大喊“嘿,更新所有内容!”,因此,它根据Person的当前状态重新绑定所有视图,其中当然包括“昵称”,以便更新视图。

您要做的是只更新绑定到昵称的字段,因为这是一件发生变化的事情,最好是在昵称发生变化时自动更新。为此,您需要观察昵称字段的状态,并对其变化做出反应。

您可以通过以下几种方式完成此操作:

  1. 使用LiveData

在这种方法中,您需要绑定的模型字段是对象val昵称=MutableLiveData

数据绑定设置为使用Live Data,因此您的xml不需要更改。但现在属性是可观察的,当您更新Person上的名称时(Person?.nickname?.value=“New nickname”),将自动通知数据绑定,并更新关联视图的状态。

您不必调用validateAll()

这在概念上与#1相同,但这是在引入Live Data之前出现的。现在,您可以考虑不推荐使用这种方法,并使用LiveData方法,但为了完整起见,我会提到它。

同样,您可以将该属性包装在一个可观察的数据结构中(val昵称=observatestring()),当值发生更改时,该结构将通知数据绑定,而不是使用类型为字符串的常规属性。同样,设置数据绑定就是为了使用它,所以您不必更改XML。

使用此选项,您可以使您的Person类(或者最好是视图模型)扩展为可观察的,并在字段更改时管理通知数据绑定。如果在更新某些字段时必须有特殊的逻辑,并且简单的“设置并通知”是不够的,那么您可以走这条路线。这个选项要复杂得多,我将把它作为练习留给读者阅读文档,看看这个选项是如何工作的。对于绝大多数情况,您应该能够使用选项#1执行所需操作。

这句话的离别思想:

person?.nickname = etNickname.text.toString()

如果您正确设置了数据绑定,这应该是不必要的。:)如果您设置etNickname以使用双向绑定并使person.nickname正确可观察,person.nickname属性将在更改时自动更新为etNickname中的文本值!

这就是数据绑定的美妙之处。

希望有帮助!

 类似资料:
  • 如果我没有使用spring构建图形,那么是否可以使用spring框架完全访问我的neo4j图形?我正在尝试一些示例,但它似乎无法正常工作,因为spring创建的某些元数据不存在。 编辑:例如,我有这个错误当我试图通过它的id访问一个节点时,即

  • 2.2.5版 []Linux 使用ETL导入顶点和边时,加载一些顶点和边后会出现超时异常。 -year . CSV:id _ year | year 1 | 2010年2 | 2011年3 | 2012年4 | 2013年5 | 2014年6 | 2015年7 | 2016年8 | 2017年 - 月.csv:id_month |月 |第|季度年 1 || 年 1 月日本金融|2010 2 |2

  • 但现在,有些服务会变成空的。是否有方法在@Runwith注释中同时使用SpringJunit4ClassRunner.class和PowerMockRunner.class

  • 我运行下面的脚本时出错,我不知道如何更正它。本质上,我在mysql中有一个名为gamestbl的表。我希望用户输入一些关于游戏名称或游戏描述的关键词,然后php将正确的游戏显示为下拉列表(理想情况下)甚至信息表。 错误显示: 警告:mysqli_query()至少需要2个参数,其中1个参数在第29行的C:\xampp\htdocs\introductiongphp\Email.php中给出 警告:

  • 我的gradle文件中有以下数据绑定依赖项

  • 请问这是什么原因? 官方文档里的代码复制下来也是错误的