Jetpack系列(五) -- DataBinding

DataBinding

前言

时间: 23/09/18 (牢记 九·一八 事变)

AndroidStudio版本: Giraffe 2022.3.1 JDK:17 开发语言: Kotlin

Gradle版本: 8.0 Gradle plugin Version: 8.1.1

概述

上一篇讲述了 ViewBinding 的使用,ViewBinding 能够简化绑定视图的代码。本篇就了解一下 DataBinding 组件,它和 ViewBinding 一样,也可以引用视图的 id 来实现交互,但是 DataBinding 有更加丰富的功能。其次 DataBinding 也是实现MVVM框架的重要组件之一。

DataBinding 的基本使用

简单的视图绑定功能

  • 添加配置

    在build.gradle(app)中添加

    groovy 复制代码
    android {
        ...
        ...
    	buildFeatures {
            dataBinding = true
        }
    }
  • 修改 Layout.xml 文件

    在最新版本的 Gradle 中,使用 DataBinding 必须要给布局文件添加 <layout> 标签。否则无法正常build工程。

    在 xml 文件最外围添加 layout 标签

    xml 复制代码
    <?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:tools="http://schemas.android.com/tools"
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto">
        <data> 如果只使用viewbinding的功能,data标签可加可不加
            
        </data>
        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            tools:context=".MainActivity">
    	...
        ...
    
        </androidx.constraintlayout.widget.ConstraintLayout>
    </layout>
  • 在 Activity 中的修改和使用 ViewBinding 是一致的

    添加一个全局 ActivityMainBinding 变量,inflate 实例化即可使用

    kotlin 复制代码
    class MainActivity : AppCompatActivity() {    
        private lateinit var binding: ActivityMainBinding
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            binding = ActivityMainBinding.inflate(layoutInflater)
            setContentView(binding.root)
        }
    }

数据视图单向绑定

  • 给上面提到的 xml 中添加的<data>标签添加属性

    xml 复制代码
        <data>
            <variable
                name="point"
                type="Int" />
        </data>

    name 就是后续需要调用的,类似于代码中的变量名,而type 就是 name 的类型。

    当然也可以使用自定义的实体类。

    xml 复制代码
        <data>
            <variable
                name="user"
                type="com.example.part_6.entity.User" />
        </data>

    定义了一个User类,名称为 user 。

    kotlin 复制代码
    data class User(var id: String, var name: String)
  • 在 xml 中的TextView视图控件中添加 @{}

    xml 复制代码
            <TextView
                android:id="@+id/tv_username"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{user.name}"
                android:textSize="24sp" />
    
            <TextView
                android:id="@+id/tv_id"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{user.id}"
                android:textSize="18sp" />
    
            <androidx.appcompat.widget.AppCompatButton
                android:id="@+id/submit_info"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="submit"
                android:layout_marginTop="38dp" />

    添加一个按钮,点击响应相关事件实现单向绑定。具体的布局可以自己写,我这边省略了布局控制相关的代码。需要demo源码请在文末获取。

  • 在 Activity 中进行数据绑定

    kotlin 复制代码
    //MainActivity
    class MainActivity : AppCompatActivity() {    
        private lateinit var binding: ActivityMainBinding
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            binding = ActivityMainBinding.inflate(layoutInflater)
            setContentView(binding.root)
            binding.submitInfo.setOnClickListener {
                val id = binding.etId.text.toString().trim()
                val name = binding.etUsername.text.toString().trim()
                val user = User(id, name)
                binding.user = user
                //只需要将user数据传给<data>,在xml中会自动分配user.name和user.id
            }
        }
    }
    单向绑定结果图

数据视图双向绑定

这是实现MVVM的关键,感兴趣的可以仔细看看。

上面的例子呢,需要点击按钮,响应后读取edit中的数据,然后通过单向绑定将 数据 传给 text_view 。我们能否省略这个点击后获取数据的步骤呢?Of course yes. 并且方案不止一种,我们可以给Edit_Text添加数据变化监听,但是这种方式不涉及databinding,这里就不细说了,具体可以查一查 addTextChangedListener 这个API。

而双向绑定就是更为便捷,代码更简单的一种方式。

  • 新建一个 UserBind 继承BaseObservable(),给属性的 getter 添加 Bindable 注释,并给setter添加 notifyPropertyChanged 方法。

    kotlin 复制代码
    class UserBind: BaseObservable() {
    
        @get:Bindable
        var name: String = ""
            set(value) {
                field = value
                notifyPropertyChanged(BR.name)
            }
        @get:Bindable
        var id: String = ""
            set(value) {
                field = value
                notifyPropertyChanged(BR.id)
            }
    }

    BaseObservable是一种可观察数据,继承自它的数据类负责在更新是发出通知。

  • 更改 xml 中 EditText 的 text 属性为 @={}

    xml 复制代码
    				...
                <com.google.android.material.textfield.TextInputEditText
                    android:id="@+id/et_username"
                    android:hint="Text user name"
                    android:text="@={userBind.name}"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content" />
    				...
                <com.google.android.material.textfield.TextInputEditText
                    android:id="@+id/et_id"
                    android:hint="Text user id"
                    android:text="@={userBind.id}"
                    android:inputType="number"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content" />
  • 在 Activity 中绑定 UserBind 对象

    kotlin 复制代码
    class MainActivity : AppCompatActivity() {
    
        private lateinit var binding: ActivityMainBinding
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            binding = ActivityMainBinding.inflate(layoutInflater)
            setContentView(binding.root)
            val userBind = UserBind()
            binding.userBind = userBind
        }
    
    }
  • 结果图

以上是使用BaseObservable来实现的 双向数据绑定,使用 BR 需要引入 kapt 插件

groovy 复制代码
plugins {
    id("com.android.application")//default
    id("org.jetbrains.kotlin.android")//default
    id("kotlin-kapt")//this one
}

使用 DataBinding 绑定点击事件

相信很多人使用点击事件时,或多或少都用到过onClick属性,然后在Activity中添加一个与onClick属性同名的函数来实现点击事件响应。而databinding的绑定点击事件其实和这个方法非常相似。

  • 添加一个ClickHandler类

    kotlin 复制代码
    class ClickHandler {
        val TAG = "ClickHandler"
    
        fun click1(view: View) {
            Log.d(TAG, "click1")
        }
    }
  • layout中引入这个类

    xml 复制代码
    ...
    	<data>
    		...
            <variable
                name="clickHandler"
                type="com.example.part_6.ClickHandler" />
        </data>
    		....
    		....
            <androidx.appcompat.widget.AppCompatButton
                android:id="@+id/click1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="50dp"
                android:onClick="@{clickHandler::click1}"
                android:text="click1" />
  • 然后在Activity中绑定这个类和视图

    kotlin 复制代码
    class MainActivity : AppCompatActivity() {
        private val TAG = "MainActivity"
    
        private lateinit var binding: ActivityMainBinding
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            binding = ActivityMainBinding.inflate(layoutInflater)
            setContentView(binding.root)
            //click bind
            binding.clickHandler = ClickHandler()
        }
    }
  • log

在现在的版本还有更高级的方法,这种方法可以传参数

  • 添加一个方法到ClickHandler中

    kotlin 复制代码
        fun click2(view: View, userBind: UserBind) {
            Log.d(TAG, "click2: user = $userBind")
        }
  • 修改 layout 中的 onClick属性

    xml 复制代码
    android:onClick="@{(view) -> clickHandler.click2(view, userBind)}"
  • Log

这种方式可以从代码中抽离部分代码到 xml 中,但是在实际开发过程中,我们的点击事件监听器可能会比较复杂,这会导致代码臃肿。所以复杂的监听器还是可以根据个人分模块或多方法实现。

总结

这节主要讲述的DataBinding的基本用法,包括单向绑定、双向绑定以及点击监听绑定。

当然,DataBinding 能实现的功能远不止于此,关于 DataBinding 的进阶用法,可以查阅相关资料。后续我也会再写一个关于jetpack进阶用法的专栏。

下节就讲述一下jetpack的数据库操作的组件 ------ room

demo地址(GitHub)

相关推荐
Kapaseker6 小时前
四大组件齐上阵,轻松拿捏实习生
android·kotlin
ljt27249606611 天前
Compose笔记(六十一)--SelectionContainer
android·笔记·android jetpack
Kapaseker1 天前
三分钟搞懂 Kotlin Flow 中的背压
android·kotlin
QING6181 天前
Jetpack Compose 中的 ViewModel 作用域管理 —— 新手指南
android·kotlin·android jetpack
惟恋惜2 天前
Jetpack Compose 的状态使用之“界面状态”
android·android jetpack
KotlinKUG贵州2 天前
Kotlin/Ktor 实践:利用 MCP 从零打造 AI Agent 服务端指南
kotlin·agent·mcp
喜熊的Btm2 天前
探索 Kotlin 的不可变集合库
kotlin·android jetpack
惟恋惜2 天前
Jetpack Compose 界面元素状态(UI Element State)详解
android·ui·android jetpack
惟恋惜2 天前
Jetpack Compose 多页面架构实战:从 Splash 到底部导航,每个 Tab 拥有独立 ViewModel
android·ui·架构·android jetpack