【Jetpack】DataBinding 架构组件 ⑤ ( 数据模型与视图双向绑定 | BaseObservable 实现双向绑定 | ObservableField 实现双向绑定 )

这篇具有很好参考价值的文章主要介绍了【Jetpack】DataBinding 架构组件 ⑤ ( 数据模型与视图双向绑定 | BaseObservable 实现双向绑定 | ObservableField 实现双向绑定 )。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。





一、数据模型 Model 与视图 View 双向绑定




1、数据模型 Model 与视图 View 的单向绑定


在之前的博客中 ,

数据模型 Model 中的 指定 Field 字段 绑定到 View 视图中的组件 ,

在实际案例中 , 将 Student 类中的 String 类型的 name 字段绑定到了 布局文件中的 TextView 组件中 ,

当 Student#name 字段发生了改变 ,

对应的 TextView 组件中显示的内容也发生了相应的修改 ;


上述绑定方式可以理解为 单向绑定 ,

因为 TextView 组件不能修改 , 只能显示 ,

数据模型中的字段修改 , 可以改变 TextView 显示的内容 ;

TextView 组件不能发起对数据模型的修改 ;

【Jetpack】DataBinding 架构组件 ⑤ ( 数据模型与视图双向绑定 | BaseObservable 实现双向绑定 | ObservableField 实现双向绑定 )


2、由单向绑定引出双向绑定


如果 绑定的 数据模型 对应的组件是 EditText 文本框 ,

EditText 组件的内容可以自行进行修改 ,

数据模型 可以发起对 EditText 组件的修改 ,

同时 EditText 也可以发起对数据模型的修改 ,

那么就会出现一个 双向绑定 的问题 ;

【Jetpack】DataBinding 架构组件 ⑤ ( 数据模型与视图双向绑定 | BaseObservable 实现双向绑定 | ObservableField 实现双向绑定 )





二、BaseObservable 实现数据模型 Model 与视图 View 双向绑定



示例代码 : https://download.csdn.net/download/han1202012/87702558


1、启用 DataBinding


使用 DataBinding 前 , 必须启用数据绑定 ,

Module 下的 build.gradle 构建脚本 中 , 在 " android / defaultConfig " 层级 , 配置

        // 启用 DataBinding
        dataBinding {
            enabled = true
        }

内容 , 即可启用 数据绑定 ;


完整层级的代码如下 :

android {
    namespace 'kim.hsl.databinding_demo'
    compileSdk 32

    defaultConfig {
        applicationId "kim.hsl.databinding_demo"
        minSdk 21
        targetSdk 32

        // 启用 DataBinding
        dataBinding {
            enabled = true
        }
    }
}

2、导入 kotlin-kapt 插件


凡是 在 Kotlin 中使用到注解的情况下 , 都需要导入 kotlin-kapt 插件 ;

在 Module 下的 build.gradle 构建脚本中 , 导入 kotlin-kapt 插件 ;

plugins {
    id 'kotlin-kapt'
}

3、数据模型类


数据类中 , 主要 封装 数据模型 ;

package kim.hsl.databinding_demo

class Student(var name: String, var age: Int) {
}

4、BaseObservable 实现双向绑定 ( 本博客的核心重点 ) ★


实现 数据 与 视图 的双向绑定类 , 需要继承 BaseObservable 类 ;


class StudentViewModel: BaseObservable {
}

在该类中 , 需要 维护一个 数据类对象 , 如下在 次构造函数 中传入 ;

    lateinit var student: Student

    constructor() {
        this.student = Student("Tom", 18)
    }

实现一个 getXxx 函数 , 使用 @Bindable 注解修饰该函数 ,

同时 在 DataBinding 布局中 , 为 EditText 组件设置值时 , 也使用该函数设置值 ;

设置了 @Bindable 注解 , 只要 student 对象中的 name 发生了变化 , 绑定的组件中的内容就会发生变化 ;

    /**
     * 只要 student 对象中的 name 发生了变化
     * 绑定的组件中的内容就会发生变化
     */
    @Bindable
    fun getStudentName(): String {
        return student.name
    }

如果要实现 通过 EditText 修改 数据模型 的效果 , 需要再实现一个 setXxx 函数 ,

该函数需要与之前的 使用 @Bindable 注解修饰的 getXxx 函数对应 , Xxx 必须是一样的 ;

修改后需要调用 notifyPropertyChanged(BR.xxx) 通知数据模型进行变更 ;

    /**
     * 只要绑定的 EditText 组件内容发生变化
     * 就会自动调用该函数 修改 student 对象中的 name 字段
     */
    fun setStudentName(name: String): Unit {
        // 修改后的字符串不为空 且与之前的值不同 才更新数据模型数据
        if (name != null && !(name == student.name)) {
            student.name = name
            Log.i("StudentViewModel", "setStudentName : ${name}")

            // BR 是编译时自动生成的字段
            // studentName 对应的是 上面 被 @Bindable 修饰的 getStudentName 函数
            notifyPropertyChanged(BR.studentName)
        }
    }

BR 类是 BaseObservable 子类中由 @Bindable 注解修饰的函数生成 ;

BR 类生成位置在 app\build\generated\source\kapt\debug\kim\hsl\databinding_demo\BR.java ;

【Jetpack】DataBinding 架构组件 ⑤ ( 数据模型与视图双向绑定 | BaseObservable 实现双向绑定 | ObservableField 实现双向绑定 )


BaseObservable 类源码如下 :

package kim.hsl.databinding_demo

import android.util.Log
import android.view.View
import androidx.databinding.BaseObservable
import androidx.databinding.Bindable

class StudentViewModel: BaseObservable {

    lateinit var student: Student

    constructor() {
        this.student = Student("Tom", 18)
    }

    /**
     * 只要 student 对象中的 name 发生了变化
     * 绑定的组件中的内容就会发生变化
     */
    @Bindable
    fun getStudentName(): String {
        return student.name
    }

    /**
     * 只要绑定的 EditText 组件内容发生变化
     * 就会自动调用该函数 修改 student 对象中的 name 字段
     */
    fun setStudentName(name: String): Unit {
        // 修改后的字符串不为空 且与之前的值不同 才更新数据模型数据
        if (name != null && !(name == student.name)) {
            student.name = name
            Log.i("StudentViewModel", "setStudentName : ${name}")

            // BR 是编译时自动生成的字段
            // studentName 对应的是 上面 被 @Bindable 修饰的 getStudentName 函数
            notifyPropertyChanged(BR.studentName)
        }
    }
}

5、布局文件设置 ( 重点 )


在 DataBinding 布局文件中 , 需要 在 " data / variable " 标签中 , 引入 StudentViewModel 类型的对象 ;

在位 EditText 组件赋值时 , 需要使用 android:text="@={student.studentName}" 进行赋值 , 注意值为 @={student.studentName} , 比之前的数据绑定多了一个等号 ;


布局代码示例 :

<?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>
        <variable
            name="student"
            type="kim.hsl.databinding_demo.StudentViewModel" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <EditText
            android:id="@+id/imageView"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:text="@={student.studentName}"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"/>

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

6、Activity 组件代码 ( 重点 )


在 Activity 组件中 , 向布局中设置的对象类型是 StudentViewModel 类型的 , 不是 Student 类型的 ;

package kim.hsl.databinding_demo

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import kim.hsl.databinding_demo.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // 设置布局文件
        // 布局文件是 activity_main.xml
        // 该类名称生成规则是 布局文件名称 + Binding
        var activityMainBinding: ActivityMainBinding =
            DataBindingUtil.setContentView(this, R.layout.activity_main)

        // 为布局 设置 数据
        activityMainBinding.student = StudentViewModel()
    }
}

7、执行结果


执行后显示 :

【Jetpack】DataBinding 架构组件 ⑤ ( 数据模型与视图双向绑定 | BaseObservable 实现双向绑定 | ObservableField 实现双向绑定 )

逐个字母删除 Tom , 然后输入 Jack ;

最终打印如下日志 :

setStudentName : To
setStudentName : T
setStudentName : 
setStudentName : Jack

【Jetpack】DataBinding 架构组件 ⑤ ( 数据模型与视图双向绑定 | BaseObservable 实现双向绑定 | ObservableField 实现双向绑定 )

【Jetpack】DataBinding 架构组件 ⑤ ( 数据模型与视图双向绑定 | BaseObservable 实现双向绑定 | ObservableField 实现双向绑定 )





三、ObservableField 实现数据模型 Model 与视图 View 双向绑定 ( 本博客的核心重点 ) ★



示例代码 :


ObservableField 实现数据模型 Model 与视图 View 双向绑定

BaseObservable 实现数据模型 Model 与视图 View 双向绑定

进行对比 ,

除了 StudentViewModel 之外 , 其它代码都一样 ;

重点介绍 StudentViewModel 类 ;


将数据模型类 Student , 定义为 ObservableField 的泛型类 ;

    lateinit var studentObservableField: ObservableField<Student>

在构造函数中 , 创建 Student 对象 , 将其设置到 ObservableField<Student> 对象中 ;

    constructor() {
        var student: Student = Student("Tom", 18)
        studentObservableField = ObservableField()
        studentObservableField.set(student)
    }

定义 getStudentName() 函数 , 获取 ObservableField<Student> 对象中的 Student 对象的 name 属性 ;

    fun getStudentName(): String? {
        return studentObservableField.get()?.name
    }

定义 setStudentName() 函数 , 设置 ObservableField<Student> 对象中的 Student 对象的 name 属性 ;

    fun setStudentName(name: String): Unit {
        studentObservableField.get()?.name = name
        Log.i("StudentViewModel", "setStudentName : ${name}")
    }

完整代码如下 :

package kim.hsl.databinding_demo

import android.util.Log
import androidx.databinding.ObservableField

class StudentViewModel {
    lateinit var studentObservableField: ObservableField<Student>

    constructor() {
        var student: Student = Student("Tom", 18)
        studentObservableField = ObservableField()
        studentObservableField.set(student)
    }

    fun getStudentName(): String? {
        return studentObservableField.get()?.name
    }

    fun setStudentName(name: String): Unit {
        studentObservableField.get()?.name = name
        Log.i("StudentViewModel", "setStudentName : ${name}")
    }
}

执行上述代码 , 也能实现与 BaseObservable 双向绑定相同的效果 ;
【Jetpack】DataBinding 架构组件 ⑤ ( 数据模型与视图双向绑定 | BaseObservable 实现双向绑定 | ObservableField 实现双向绑定 )文章来源地址https://www.toymoban.com/news/detail-420395.html

到了这里,关于【Jetpack】DataBinding 架构组件 ⑤ ( 数据模型与视图双向绑定 | BaseObservable 实现双向绑定 | ObservableField 实现双向绑定 )的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Jetpack】DataBinding 架构组件 ② ( 字符串拼接函数 | 绑定点击事件函数 | DataBinding 布局中使用 import 标签导入 Java、Kotlin 类 )

    在上一篇博客中 , 遇到 在 DataBinding 布局 中 , 向 TextView 组件设置 int 类型数据的情况会报错 , 最终的处理方式是 将 int 类型的变量 student.age 通过 String.valueOf 函数转为 字符串 类型 , 设置到 TextView 组件中 ; 此外 , 还可以 在 数据类 中定义 字符串拼接函数 , 直接在 DataBinding 布局

    2023年04月08日
    浏览(84)
  • Jetpack业务架构—四件套(Lifecycle、ViewModel、LiveData、DataBinding)

    Jetpack 是一个由多个库组成的套件,可帮助开发者遵循最佳做法、减少样板代码并编写可在各种 Android 版本和设备中一致运行的代码,让开发者可将精力集中于真正重要的编码工作。 Android Jetpack组件的优势: Jetpack推出的主要目的是为了能够让开发者更加快速、方便以及高质

    2024年02月09日
    浏览(38)
  • android jetpack databinding的基本使用(java)

    开启databing 修改布局文件 为布局文件添加layout标签。 实例化布局文件 向布局文件传递数据 创建一个Sentence 类,实例化。传给布局并显示。 5. 在布局中引用静态类 在sentence类中添加属性collect ,collect 等于1表示已收藏,0表示收藏。 建立工具类CollectUtil 通过import导入到布局文

    2024年02月10日
    浏览(38)
  • Android Jetpack组件架构:ViewModel的原理

    本篇文章是关于介绍ViewModel的,由于ViewModel的使用还是挺简单的,这里就不再介绍其的基本应用,我们主要来分析ViewModel的原理。 众所周知,一般使用ViewModel是用来解决两个问题的,第一个就是关于设备配置发生改变时Activity先前状态的保存,在ViewModel出来之前我们一般会使

    2024年02月07日
    浏览(40)
  • 【Jetpack】ViewModel + LiveData + DataBinding 综合使用 ( 核心要点说明 | 组合方式 | 代码示例 )

    ViewModel 架构组件 是 视图 View 与 数据模型 Model 之间 数据交互的 桥梁 ; 传统 Android 开发中 , 视图 View 与 数据模型 Model 都在 Activity 中维护 , 导致 二者有很高的耦合度 , 不利于代码维护 ; 引入了 ViewModel 架构组件后 , 视图 View 与 数据模型 Model 之间实现了解耦 , 同时也能 保证二

    2024年02月01日
    浏览(44)
  • 【Qt之模型视图】1. 模型和视图架构

    MVC(Model-View-Control)是一种源自 Smalltalk 的设计模式,通常用于构建用户界面。 MVC由三种类型的对象组成。模型是应用对象,用来表示数据;视图是模型的用户界面,用来显示数据;控制器定义了用户界面对用户输入的反应方式。在MVC之前,用户界面设计往往将这些对象混为

    2024年01月18日
    浏览(54)
  • 大型Android项目架构:基于组件化+模块化+Kotlin+协程+Flow+Retrofit+Jetpack+MVVM架构实现WanAndroid客户端

    前言:苟有恒,何必三更眠五更起;最无益,莫过一日曝十日寒。 之前一直想写个 WanAndroid 项目来巩固自己对 Kotlin+Jetpack+协程 等知识的学习,但是一直没有时间。这里重新行动起来,从项目搭建到完成前前后后用了两个月时间,平常时间比较少,基本上都是只能利用零碎的

    2024年02月09日
    浏览(53)
  • SpringMVC的架构有什么优势?——视图与模型(二)

    「作者主页」 :雪碧有白泡泡 「个人网站」 :雪碧的个人网站 「推荐专栏」 : ★ java一站式服务 ★ ★ React从入门到精通 ★ ★ 前端炫酷代码分享 ★ ★ 从0到英雄,vue成神之路★ ★ uniapp-从构建到提升 ★ ★ 从0到英雄,vue成神之路 ★ ★ 解决算法,一个专栏就够了 ★ ★

    2024年02月13日
    浏览(53)
  • 《Jetpack Compose从入门到实战》第三章 定制 UI 视图

    -ui.theme.Color.kt ui.theme.Type.kt 先将Nunito Sans字体家族放入 res/font,再根据设计稿写代码 ui.theme/Shape.kt CompositionLocal 是 Jetpack Compose 中的一种数据传递方式。它可以在组合组件之间传递可变数据,而无需通过 props 或 state 管理器来传递数据。这个特性比传统的数据传递方式更为高效

    2024年02月07日
    浏览(46)
  • Vue父子组件间数据的双向绑定

    在vue中数据的流向通常是单向的,但是实际开发中,存在子组件对父组件值进行更新的情况,例如对表单组件进行二次封装等,父组件需要响应子组件的变化。双向绑定呼之欲出,vue提供了两种方法进行双向绑定: 在父组件上 v-model 会利用子组件名为 value 的 prop 和名为 inp

    2024年02月06日
    浏览(55)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包