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)

相关推荐
闲暇部落5 小时前
‌Kotlin中的?.和!!主要区别
android·开发语言·kotlin
长亭外的少年21 小时前
Kotlin 编译失败问题及解决方案:从守护进程到 Gradle 配置
android·开发语言·kotlin
JIAY_WX21 小时前
kotlin
开发语言·kotlin
麦田里的守望者江1 天前
KMP 中的 expect 和 actual 声明
android·ios·kotlin
菠菠萝宝1 天前
【YOLOv8】安卓端部署-1-项目介绍
android·java·c++·yolo·目标检测·目标跟踪·kotlin
恋猫de小郭1 天前
Kotlin Multiplatform 未来将采用基于 JetBrains Fleet 定制的独立 IDE
开发语言·ide·kotlin
枫__________2 天前
kotlin 协程 job的cancel与cancelAndJoin区别
android·开发语言·kotlin
鸠摩智首席音效师2 天前
如何在 Ubuntu 上配置 Kotlin 应用环境 ?
linux·ubuntu·kotlin
jikuaidi6yuan4 天前
Java与Kotlin在鸿蒙中的地位
java·kotlin·harmonyos
liulanba4 天前
Kotlin的data class
前端·微信·kotlin