Android开发Jetpack组件DataBinding用例详解

目录
  • 简介
  • 使用方式
    • 1. build.gradle 中添加 kapt,并启用dataBinding
    • 2.修改布局文件,添加 layout 和 data 标签
    • 3.使用 DataBindingUtil 绑定布局
    • 4.布局的 data 标签中添加数据变量,并使用其参数
    • 5.BindingAdapter的使用

简介

DataBinding 是 Jetpack 组件之一,适用于 MVVM 模式开发,也是Google官方推荐使用的组件之一。使用DataBinding可以很容易的达到视图与逻辑分离,直接在布局中绑定数据,并且数据改变时自动更新UI,不再需要在业务代码中绑定数据。

本文结合Google官方提供的DataBinding使用示例讲解,Google官方sample地址:

https://github.com/googlesamples/android-databinding

其中包含两个工程,本文使用的BasicSample工程。

使用方式

1. build.gradle 中添加 kapt,并启用dataBinding

在app模块的build.gradle文件中,添加:

apply plugin: 'kotlin-kapt'
android {
    ...
    dataBinding {
        enabled true
    }
}

其中,apply plugin: 'kotlin-kapt'是为了在Kotlin中使用BindingAdapter注解。

2.修改布局文件,添加 layout 和 data 标签

使用DataBinding的布局文件与普通的布局文件有些不同,在布局外需要包裹一层<layout>,并添加<data>标签,如下所示:

<?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"
        xmlns:tools="http://schemas.android.com/tools">
    <data/>
    <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

<data>标签是用来添加数据的,初次使用,先保持为空即可。<data>标签之后就是正常的布局代码,与普通的布局代码一模一样。
接下来,我们在activity_main布局中添加两个按钮:

<?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"
        xmlns:tools="http://schemas.android.com/tools">
    <data/>
    <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">
        <Button
                android:id="@+id/observable_fields_activity_button"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="8dp"
                android:text="Observable Fields activity"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent"/>
        <Button
                android:id="@+id/viewmodel_activity_button"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="8dp"
                android:text="ViewModel activity"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@id/observable_fields_activity_button"/>
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

写好布局文件后rebuild project,这时generatedJava文件夹下会自动生成databinding需要用到的文件。

3.使用 DataBindingUtil 绑定布局

由于使用了DataBinding布局,所以我们需要用DataBindingUtil绑定布局,而不是直接使用setContentView。

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // 因为使用了dataBinding布局,所以这里需要用DataBindingUtil来设置布局
        val binding: ActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
        // 返回的binding拥有布局中所有的View,使用id引用即可
        binding.observableFieldsActivityButton.setOnClickListener {
            startActivity(Intent(this, ObservableFieldActivity::class.java))
        }
        binding.viewmodelActivityButton.setOnClickListener {
            startActivity(Intent(this, ViewModelActivity::class.java))
        }
    }
}

返回的Binding类型跟布局文件名有关,规则是布局文件名去掉下划线,改成驼峰命名,再添加Binding后缀。比如本例中使用的布局文件是activity_main.xml,所以返回的Binding类型就是ActivityMainBinding。
返回的binding中拥有布局中的所有View,使用id即可引用,这里我们给两个按钮添加了两个点击事件,点击跳转至另外两个Activity。这里我们先新建两个空的Activity,命名为ObservableFieldActivity和ViewModelActivity,后面我们会修改这两个Activity的内容。注意由于使用了DataBinding布局,所以Kotlin直接用id引用View的特性不可用了。

4.布局的 data 标签中添加数据变量,并使用其参数

<layout>中的<data>用来定义需要绑定的数据,我们先新建一个数据类ObservableFieldProfile:

data class ObservableFieldProfile(
        val name: String,
        val lastName: String
)

这是一个表示个人信息的类,name表示名字,lastName表示姓氏。

在ObservableFieldActivity的布局文件中,使用此类定义一个user变量:

<?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"
        xmlns:tools="http://schemas.android.com/tools">
    <data>
        <import type="com.example.studydatabinding.data.ObservableFieldProfile"/>

        <variable
                name="user"
                type="ObservableFieldProfile"/>
    </data>
    <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            tools:context=".ui.ObservableFieldActivity">

        <TextView
                android:id="@+id/name_label"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginStart="16dp"
                android:layout_marginTop="8dp"
                android:text="Name"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent"/>
        <TextView
                android:id="@+id/name"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="8dp"
                android:text="@{user.name}"
                app:layout_constraintStart_toStartOf="@id/name_label"
                app:layout_constraintTop_toBottomOf="@id/name_label"/>
        <TextView
                android:id="@+id/lastname_label"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="8dp"
                android:text="Last Name"
                app:layout_constraintStart_toStartOf="@id/name"
                app:layout_constraintTop_toBottomOf="@id/name"/>
        <TextView
                android:id="@+id/lastname"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="8dp"
                android:text="@{user.lastName}"
                app:layout_constraintStart_toStartOf="@id/lastname_label"
                app:layout_constraintTop_toBottomOf="@id/lastname_label"/>
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

<data>中的import标签用于导入使用的类,type表示类的完整路径,<variable>标签用于定义变量,name表示变量名,type表示变量类型。在此例中,我们定义了一个类型为ObservableFieldProfile的user变量。
使用此变量的方式也很简单,在布局文件中,使用@{user.name}即可使用user变量的name参数,使用@{user.lastName}即可使用user变量的lastName参数。可以看到,我们给两个TextView的android:text属性设置了user的这两个参数。

同样的,写好布局文件后需要rebuild Project。

在ObservableFieldActivity中,使用DataBindingUtil设置布局,并且给返回的binding变量设置user参数,代码如下:

class ObservableFieldActivity : AppCompatActivity() {
    private val observableFieldProfile = ObservableFieldProfile("Alpinist", "Wang")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding: ActivityObservableFieldBinding = DataBindingUtil.setContentView(this, R.layout.activity_observable_field)
        binding.user = observableFieldProfile
    }
}

使用binding.user给DataBinding布局中的user变量赋值。
此时,运行程序,显示如下:

可以看到,我们绑定的user变量已经成功显示出来了。

不过此时user变量变化时,UI还不能自动刷新。如果需要UI随着变量自动刷新,需要将String类型换成ObservableField<String>类型。如果是int型变量,需要替换成ObservableField<Int>类型,它等同于ObservableInt类型,我们以ObservableInt类型为例,在ObservableFieldProfile类中新增likes变量,:

data class ObservableFieldProfile(
    val name: String,
    val lastName: String,
    val likes: ObservableInt
)

修改布局文件activity_observable_field.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"
        xmlns:tools="http://schemas.android.com/tools">
    ...
    <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">
        ...
        <TextView
        		android:id="@+id/likes_label"
                android:text="Like"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintTop_toTopOf="parent"
                android:layout_marginEnd="8dp"
                android:layout_marginTop="8dp"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>
        <TextView
                android:id="@+id/likes"
                app:layout_constraintTop_toBottomOf="@id/likes_label"
                app:layout_constraintStart_toStartOf="@id/likes_label"
                app:layout_constraintEnd_toEndOf="@id/likes_label"
                android:text="@{Integer.toString(user.likes)}"
                android:layout_marginTop="8dp"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>
        <Button
                android:id="@+id/like_button"
                app:layout_constraintTop_toBottomOf="@id/likes"
                app:layout_constraintEnd_toEndOf="parent"
                android:layout_marginTop="8dp"
                android:layout_marginEnd="8dp"
                android:text="Like"
                android:onClick="onLike"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

我们在布局中添加了一个按钮,点击一次触发onLike方法,还添加了一个显示likes数量的TextView,由于likes是一个Int型变量,所以我们用Integer.toString()方法将其转换为了String。

修改ObservableFieldActivity:

class ObservableFieldActivity : AppCompatActivity() {
    private val observableFieldProfile = ObservableFieldProfile("Alpinist", "Wang", ObservableInt(0))
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding: ActivityObservableFieldBinding =
            DataBindingUtil.setContentView(this, R.layout.activity_observable_field)
        binding.user = observableFieldProfile
    }
    fun onLike(view: View) {
        observableFieldProfile.likes.increment()
    }
}
fun ObservableInt.increment() {
    set(get() + 1)
}

我们在此Activity中添加了onLike()方法,前文已说到,点击按钮一次便会触发一次onLike方法,在此方法中,我们将user的likes变量增加1。其中拓展的increment函数主要是为了方便调用。
此时,运行程序,效果如下:

为了让效果更加酷炫一点,顺便复习一下上面学到的内容,我们在布局中添加一个ImageView和一个ProgressBar:

<?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"
        xmlns:tools="http://schemas.android.com/tools">
    <data>
        <import type="com.example.studydatabinding.data.ObservableFieldProfile"/>
        <import type="android.view.View"/>
        <variable
                name="user"
                type="ObservableFieldProfile"/>
    </data>
    <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            tools:context=".ui.ObservableFieldActivity">
        <TextView
                android:id="@+id/name_label"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginStart="16dp"
                android:layout_marginTop="8dp"
                android:text="Name"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent"/>
        <TextView
                android:id="@+id/name"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="8dp"
                android:text="@{user.name}"
                app:layout_constraintStart_toStartOf="@id/name_label"
                app:layout_constraintTop_toBottomOf="@id/name_label"/>
        <TextView
                android:id="@+id/lastname_label"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="8dp"
                android:text="Last Name"
                app:layout_constraintStart_toStartOf="@id/name"
                app:layout_constraintTop_toBottomOf="@id/name"/>
        <TextView
                android:id="@+id/lastname"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="8dp"
                android:text="@{user.lastName}"
                app:layout_constraintStart_toStartOf="@id/lastname_label"
                app:layout_constraintTop_toBottomOf="@id/lastname_label"/>
        <ImageView
                android:minHeight="48dp"
                android:minWidth="48dp"
                android:id="@+id/imageView"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                android:layout_marginEnd="24dp"
                android:layout_marginTop="24dp"
                android:tint="@{user.likes > 9 ? @android:color/holo_red_light : @android:color/black}"
                android:src="@{user.likes < 4 ? @drawable/ic_person_black_96dp : @drawable/ic_whatshot_black_96dp}"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>
        <TextView
                android:text="Like"
                app:layout_constraintEnd_toEndOf="@id/imageView"
                app:layout_constraintTop_toBottomOf="@id/imageView"
                app:layout_constraintStart_toStartOf="@id/imageView"
                android:layout_marginEnd="8dp"
                android:layout_marginTop="8dp"
                android:id="@+id/likes_label"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>
        <TextView
                android:id="@+id/likes"
                app:layout_constraintTop_toBottomOf="@id/likes_label"
                app:layout_constraintStart_toStartOf="@id/likes_label"
                app:layout_constraintEnd_toEndOf="@id/likes_label"
                android:text="@{Integer.toString(user.likes)}"
                android:layout_marginTop="8dp"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>
        <Button
                android:id="@+id/like_button"
                app:layout_constraintTop_toBottomOf="@id/likes"
                app:layout_constraintEnd_toEndOf="@id/likes"
                app:layout_constraintStart_toStartOf="@id/likes"
                android:layout_marginTop="8dp"
                android:text="Like"
                android:onClick="onLike"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>
        <ProgressBar
                android:layout_width="0dp"
                app:layout_constraintStart_toStartOf="@id/like_button"
                app:layout_constraintEnd_toEndOf="@id/like_button"
                app:layout_constraintTop_toBottomOf="@id/like_button"
                style="@style/Widget.AppCompat.ProgressBar.Horizontal"
                android:visibility="@{user.likes > 0 ? View.VISIBLE : View.GONE}"
                android:layout_marginTop="8dp"
                android:layout_height="wrap_content"/>
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

其中的两张Vector图片代码如下:

ic_whatshot_black_96dp.xml:

<vector android:height="96dp" android:viewportHeight="24.0"
    android:viewportWidth="24.0" android:width="96dp" xmlns:android="http://schemas.android.com/apk/res/android">
    <path android:fillColor="#FF000000" android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z"/>
</vector>

ic_whatshot_black_96dp.xml:

<vector android:height="96dp" android:viewportHeight="24.0"
    android:viewportWidth="24.0" android:width="96dp" xmlns:android="http://schemas.android.com/apk/res/android">
    <path android:fillColor="#FF000000" android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z"/>
</vector>

主要添加的逻辑有:

  • 如果user.likes大于9,ImageView显示红色,否则显示黑色。
  • 如果user.likes小于4,ImageView显示ic_person_black_96dp图片,否则显示ic_whatshot_black_96dp图片。注意不能直接使用>、<符号,需要用转义字符&gt;、&lt;代替。
  • 如果user.likes大于0,显示ProgressBar,否则隐藏ProgressBar

此时,运行代码,效果如下:

5.BindingAdapter的使用

BindingAdapter是用来拓展属性的,新建一个BindingAdapters类,添加以下代码:

object BindingAdapters {
    @BindingAdapter("hideIfZero")
    @JvmStatic
    fun hideIfZero(view: View, number: Int) {
        view.visibility = if (number == 0) View.GONE else View.VISIBLE
    }
}

写好后,rebuild project,然后就可以在布局文件中,对View使用hideIfZero属性了。BindingAdapter中的参数表示属性名字,函数中的第一个参数表示View类型,后面的参数表示属性的值。
BindingAdapter中的属性名字可以添加命名空间前缀,例如可以写作app:hideIfZero,不过这样的话在xml中就只能使用app:前缀了。如果像上例中一样,在BindingAdapter中不添加命名空间前缀,那么在xml中可以直接使用hideIfZero或者其他任何除android:外的前缀,比如app:hideIfZerowhatever:hideIfZero等等。
在BindingAdapter中再添加几个扩展属性:

object BindingAdapters {
    @BindingAdapter("popularityIcon")
    @JvmStatic
    fun popularityIcon(view: ImageView, popularity: Popularity) {
        val color = getAssociateColor(popularity, view.context)
        ImageViewCompat.setImageTintList(view, ColorStateList.valueOf(color))
        view.setImageDrawable(getDrawablePopularity(popularity, view.context))
    }
    @BindingAdapter("progressTint")
    @JvmStatic
    fun tintPopularity(view: ProgressBar, popularity: Popularity) {
        val color = getAssociateColor(popularity, view.context)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            view.progressTintList = ColorStateList.valueOf(color)
        }
    }
    @BindingAdapter("progressScaled", "android:max")
    @JvmStatic
    fun setProgress(progressBar: ProgressBar, likes: Int, max: Int) {
        progressBar.progress = (likes * max / 5).coerceAtMost(max)
    }
    @BindingAdapter("hideIfZero")
    @JvmStatic
    fun hideIfZero(view: View, number: Int) {
        view.visibility = if (number == 0) View.GONE else View.VISIBLE
    }
    private fun getAssociateColor(popularity: Popularity, context: Context): Int {
        return when (popularity) {
            Popularity.POPULAR -> ContextCompat.getColor(context, R.color.popular)
            Popularity.STAR -> ContextCompat.getColor(context, R.color.star)
            else -> Color.BLACK
        }
    }
    private fun getDrawablePopularity(popularity: Popularity, context: Context): Drawable? {
        return ContextCompat.getDrawable(
            context, when (popularity) {
                Popularity.NORMAL -> R.drawable.ic_person_black_96dp
                else -> R.drawable.ic_whatshot_black_96dp
            }
        )
    }

}

从setProgress方法可以看出,如果需要获取xml中其他的属性值,在BindingAdapter中添加对应的属性名,再在函数中添加对应的参数即可。
其中的Popularity类如下:

enum class Popularity {
    NORMAL,
    POPULAR,
    STAR
}

编辑activity_view_model,使用上面定义的自定义属性:

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

    <data>
        <import type="com.example.studydatabinding.data.ProfileLiveDataViewModel"/>
        <variable
                name="viewmodel"
                type="ProfileLiveDataViewModel"/>
    </data>
    <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            tools:context=".ui.ViewModelActivity">
        <TextView
                android:id="@+id/name_label"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginStart="16dp"
                android:layout_marginTop="8dp"
                android:text="@string/name_label"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent"/>
        <TextView
                android:id="@+id/name"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="8dp"
                android:text="@{viewmodel.name}"
                app:layout_constraintStart_toStartOf="@id/name_label"
                app:layout_constraintTop_toBottomOf="@id/name_label"/>
        <TextView
                android:id="@+id/lastname_label"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="8dp"
                android:text="@string/last_name_label"
                app:layout_constraintStart_toStartOf="@id/name"
                app:layout_constraintTop_toBottomOf="@id/name"/>
        <TextView
                android:id="@+id/lastname"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="8dp"
                android:text="@{viewmodel.lastName}"
                app:layout_constraintStart_toStartOf="@id/lastname_label"
                app:layout_constraintTop_toBottomOf="@id/lastname_label"/>
        <ImageView
                android:id="@+id/imageView"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="24dp"
                android:layout_marginEnd="24dp"
                android:contentDescription="@string/profile_avatar_cd"
                android:minWidth="48dp"
                android:minHeight="48dp"
                app:popularityIcon="@{viewmodel.popularity}"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintTop_toTopOf="parent"/>
        <TextView
                android:id="@+id/likes_label"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/likes"
                app:layout_constraintEnd_toEndOf="@id/imageView"
                app:layout_constraintStart_toStartOf="@id/imageView"
                app:layout_constraintTop_toBottomOf="@id/imageView"/>
        <TextView
                android:id="@+id/likes"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{Integer.toString(viewmodel.likes)}"
                app:layout_constraintEnd_toEndOf="@id/likes_label"
                app:layout_constraintStart_toStartOf="@id/likes_label"
                app:layout_constraintTop_toBottomOf="@id/likes_label"/>
        <Button
                android:id="@+id/like_button"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="16dp"
                android:onClick="@{() -> viewmodel.onLike()}"
                android:text="@string/like"
                app:layout_constraintEnd_toEndOf="@id/likes"
                app:layout_constraintStart_toStartOf="@id/likes"
                app:layout_constraintTop_toBottomOf="@id/likes"/>
        <ProgressBar
                android:id="@+id/progressBar"
                style="@style/Widget.AppCompat.ProgressBar.Horizontal"
                android:layout_width="0dp"
                app:progressTint="@{viewmodel.popularity}"
                app:progressScaled="@{viewmodel.likes}"
                android:max="@{100}"
                android:layout_height="wrap_content"
                android:layout_marginTop="8dp"
                app:hideIfZero="@{viewmodel.likes}"
                app:layout_constraintEnd_toEndOf="@id/like_button"
                app:layout_constraintStart_toStartOf="@id/like_button"
                app:layout_constraintTop_toBottomOf="@id/like_button"/>
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

其中的ProfileLiveDataViewModel类如下:

class ProfileLiveDataViewModel : ViewModel() {
    private val _name = MutableLiveData("Alpinist")
    private val _lastName = MutableLiveData("Wang")
    private val _likes = MutableLiveData(0)
    val name: LiveData<String> = _name
    val lastName: LiveData<String> = _lastName
    val likes: LiveData<Int> = _likes
    val popularity: LiveData<Popularity> = Transformations.map(_likes) {
        when {
            it > 9 -> Popularity.STAR
            it > 4 -> Popularity.POPULAR
            else -> Popularity.NORMAL
        }
    }
    fun onLike(){
        _likes.value = _likes.value?.inc()
    }
}

LiveData也是jetpack组件之一,其原理和ObservableField是类似的,都是属于可观测的属性。
编辑ViewModelActivity:

class ViewModelActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val viewModel = ViewModelProviders.of(this).get(ProfileLiveDataViewModel::class.java)
        val binding: ActivityViewModelBinding = DataBindingUtil.setContentView(this, R.layout.activity_view_model)
        binding.viewmodel = viewModel
        binding.lifecycleOwner = this
    }
}

此时,运行程序,显示如下:

以上就是Android开发Jetpack组件DataBinding用例详解的详细内容,更多关于Android开发Jetpack组件DataBinding的资料请关注我们其它相关文章!

(0)

相关推荐

  • Android Jetpack- Paging的使用详解

    Google 推出 Jetpack 组件化已经有相当一段时间了.各种组件也层出不穷. Jetpack 的东西也不少, 今天就搞一下这个  Paging Paging 的出现,就是用作列表的分页加载.其实现在已经有非常多成熟高效的开源列表加载控件了,比如:Smartrefreshlayout等.但Google推出的,必然有它的有点,当然也有它的局限性. 先说优点吧,Paging 的使用,需要配合ViewModle,LiveData等控件,数据的请求感知并绑定页面的生命周期,避免了内存泄漏.还需要绑

  • 在Android中如何使用DataBinding详解(Kotlin)

    前言 本问主要介绍DataBinding在Android App中的使用方法.数据绑定是将"提供器"的数据源与"消费者"绑定并使其同步的一种通用技术. 1. Android应用程序使用数据绑定 1.1 介绍DataBinding Android通过DataBinding提供了编写声明型布局的支持.这样可以最大程度简化布局和逻辑相关联的代码. 数据绑定要求修改文件,外层需要包裹一个layout布局.主要通过@{} 或 @={}语法把布局中的元素和表达式的引用写入到属性

  • Android Jetpack架构组件 ViewModel详解

    前言 前面两篇文章我们已经学习了Lifecycle和DataBind,本篇文章我们来学习Jetpack系列中比较重要的ViewModel,Jetpack的很多很多组件都是搭配使用的,所以单独的知识点可能会有些"无意义"但却是我们项目实战的基础! ViewModel的使用 ViewModel类旨在以注重生命周期的方式存储和管理界面相关的数据.ViewModel类让数据可在发生屏幕旋转等配置更改后继续存在.这句话很好理解,还记得我们在讲解Lifecycle的时候 举的例子吗,我们还是使用那

  • Android Jetpack架构组件Lifecycle详解

    前言 Lifecycle是Jetpack架构组件中用来感知生命周期的组件,使用Lifecycles可以帮助我们写出和生命周期相关更简洁更易维护的代码. 生命周期 生命周期这个简单而又重要的知识相信大家早已耳熟能详.假设我们现在有这样一个简单需求: 这个需求只是一个实例,在真实的开发中当然不可能有这样的需要: 在Activity 可见的时候,我们去做一个计数功能,每隔一秒 将计数加1 ,当Activity不可见的时候停止计数,当Activity被销毁的时候 将计数置为0 OK,So easy~ ,

  • Android开发Jetpack组件DataBinding用例详解

    目录 简介 使用方式 1. build.gradle 中添加 kapt,并启用dataBinding 2.修改布局文件,添加 layout 和 data 标签 3.使用 DataBindingUtil 绑定布局 4.布局的 data 标签中添加数据变量,并使用其参数 5.BindingAdapter的使用 简介 DataBinding 是 Jetpack 组件之一,适用于 MVVM 模式开发,也是Google官方推荐使用的组件之一.使用DataBinding可以很容易的达到视图与逻辑分离,直接在

  • Android开发Jetpack组件WorkManager用例详解

    目录 一.简介 二.导入 三.基本使用 3.1 定义后台任务 3.2 配置任务运行条件 3.2.1 只需执行一次的任务 3.2.2 周期性执行的任务 3.3 将任务传给 WorkManager 四.高级配置 4.1 设置任务延迟执行 4.2 给任务添加标签 4.3 取消任务 4.3.1 根据标签取消任务 4.3.2 根据 request 的 id 取消任务 4.3.3 取消所有任务 4.4 任务重试 4.5 监听任务结果 4.6 传递数据 4.7 链式任务 一.简介 WorkManager 用于

  • Android开发Jetpack组件Room用例讲解

    目录 一.简介 二.导入 三.使用 3.1 创建 Entity 类 3.2 创建 Dao 类 3.3 创建 Database 抽象类 3.4 测试 四.数据库升级 4.1 简单升级 4.2 规范升级 4.2.1 新增一张表 4.2.2 修改一张表 4.3 测试 一.简介 Room 是 Google 官方推出的数据库 ORM 框架.ORM 是指 Object Relational Mapping,即对象关系映射,也就是将关系型数据库映射为面向对象的语言.使用 ORM 框架,我们就可以用面向对象的思

  • Android开发Jetpack Compose元素Modifier特性详解

    目录 正文 有序性 不可变性 正文 本文将会介绍Jetpack Compose中的Modifier.在谷歌官方文档中它的描述是这么一句话:Modifier元素是一个有序.不可变的集合,它可以往Jetpack Compose UI元素中添加修饰或者各种行为.例如,背景.填充和单击事件监听器装饰或添加行为到文本或按钮.本文将会从修饰符的两个特性有序和不可变入手来探究修饰符的应用,以下是本文目录: 有序性 不可变性 有序性 官方对修饰符定义的这个特性包含两个层面的意思,一是修饰符的使用是链式的它是有先

  • Android开发Jetpack组件ViewModel使用讲解

    目录 前言 ViewModel概述 ViewModel使用 ViewModel源码 前言 学习ViewModel之前首先我们得简单了解下MVP和MVVM,因为ViewModel是MVVM中的一个元素 MVP MVVM 在MVP中View想要调用Model数据层,需要经过中间层Presenter, 这样就实现了View和Model的解耦,这也是MVP和MVC的差别: 但是如果一个Activity中有太多交互,那么我们的View接口数量就会很庞大达到十几个也不足为奇,并且在View层调用了Prese

  • Android开发Jetpack组件Room使用讲解

    目录 简介 Room使用步骤 1 添加依赖 2 创建Entity实体类 3 声明Dao对象 4 声明Database对象 5 获取数据 6 最终使用 简介 Room 是 Google 官方推出的数据库 ORM 框架.ORM 是指 Object Relational Mapping,即对象关系映射,也就是将关系型数据库映射为面向对象的语言.使用 ORM 框架,我们就可以用面向对象的思想操作关系型数据库,不再需要编写 SQL 语句. Room使用步骤 1 添加依赖 build.gradle {app

  • Android开发Jetpack组件Lifecycle原理篇

    目录 前言 1.Lifecycle的生命周期状态事件和状态 2.Lifecycle如何观察Activity和Fragment的生命周期 前言 在上一篇文章中,我们学习了如何去使用Lifecycle: 当然之会使用是不够的,还需要了解它的原理,这是成为优秀工程师必备的:这篇文章就来学习Lifecycle的基本原理 1.Lifecycle的生命周期状态事件和状态 **Lifecycle使用两个枚举来跟踪其关联组件的生命周期状态,这两个枚举分别是Event和State:**State指的是Lifecy

  • Android开发Jetpack组件Lifecycle使用篇

    目录 1.为什么需要Lifecycle 2.如何使用Lifecycle 2.1 依赖Lifecycle库 2.2 Lifecycle基本用法 3.Lifecycle应用举例 3.1 Activity中使用 3.2 MVP中使用 4.自定义LifecycleOwner 1.为什么需要Lifecycle 在应用开发中,处理Activity或者Fragment组件的生命周期相关代码是必不可免的: 官方文档中举了一个例子,这里简化一下,在Activity中写一个监听,在Activity的不同生命周期方法

  • Android开发Jetpack组件LiveData使用讲解

    目录 LiveData概述 LiveData优势 共享资源 LiveData使用 1 LiveData基本使用 2 Transformations.map() 3 Transformations.switchMap() 4 MediatorLiveData.addSource()合并数据 LiveData概述 LiveData 是一种可观察的数据存储器类: 与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件(如 Activity.Fragment 或 Servi

  • Android Flutter表格组件Table的使用详解

    目录 Table.TabRow.TabCell 小结 之前开发中用到的表格,本篇文章主要介绍如何在页面中使用表格做一个记录. Table组件不同于其它Flex布局,它是直接继承的RenderObjectWidget的.相当于是一个独立的组件,区别与其他系列组件. Table.TabRow.TabCell 惯例,先看下Table相关的构造方法: Table({ Key? key, this.children = const <TableRow>[],//行列表 表示多少行 this.column

随机推荐