Android databinding之数据单向与双向绑定详解与使用(三)

news2024/12/24 8:26:31

一、介绍

        通过前面两篇文档,我们大概了解了databinding的工作方式,view的初始化,recycleview的使用。但是这些UI都离不开数据的填充,数据的修饰。

在说到数据绑定,好多开发者平时在工作中也经常听到databinding的数据绑定有简单、单向绑定、双向绑定,玄幻莫测,不敢下手。甚至有些新手听完果然放弃。接下来我会通过代码讲解databinding的数据绑定和使用,包括map、list、和用户自定义类,让复杂的事件简单化,人人都可以掌握好并使用

数据绑定

        数据绑定分为两种,一种是系统支持的,还有一种是databind的数据,接下来我们分梁部分介绍

1、系统默认数据类型

基础数据

String、int、float、double,boolean

    <data class="MyDataInfo">

        <variable
            name="name"
            type="String" />

        <variable
            name="age"
            type="int" />

        <variable
            name="bodyH"
            type="float" />

        <variable
            name="income"
            type="double" />

        <variable
            name="sex"
            type="boolean" />
    </data>

简单类型,我们直接使用即可

 布局最终引用:


        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{name}" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{String.valueOf(age)}" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{String.valueOf(bodyH)}" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{String.valueOf(income)}" />
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{String.valueOf(sex)}" />

注意:

任何在布局中的value都需要被处理成字符串类型,也就是说boolean或者double不能直接@{double}@{boolean},这种是错误的

正确:

   <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{String.valueOf(sex)}" />

错误:

   <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{sex}" />

注意:一些静态方法可以在布局中直接引用,这个后期会单独介绍

2、ArrayList、HashMap等聚合数据绑定

聚合列的数据,在data下方也是支持的,常用的有以下三种:map、list、sparseArry。

如何使用呢?因为data下方的数据都是要指定泛型的,所以这三种数据都是支持泛型,所以你必须要指定泛型。

泛型格式:

<variable
    name="list"
    type="ArrayList&lt;String&gt;" />

在type里面指定泛型。type格式=ArrayList&lt;String&gt;

这里面有人会不明白&lt;和&gt;是什么意思,

正常格式:ArrayList<String>

databind:ArrayList&lt;String&gt;

所以(&lt;   为<)左括号,(&gt;为>)右括号

    <data class="MyDataInfo">

        <import type="java.util.HashMap" />
        <import type="java.util.ArrayList" />
        <import type="android.util.SparseArray"/>

        <variable
            name="key"
            type="String" />

        <variable
            name="index"
            type="int" />

        <variable
            name="map"
            type="HashMap&lt;String,Object&gt;" />

        <variable
            name="list"
            type="ArrayList&lt;String&gt;" />

        <variable
            name="arry"
            type="SparseArray&lt;String&gt;" />

    </data>

在这里面,需要注意的是所有key和index最好动态设置,否则不方便业务开展

如何在view中绑定data数据:

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{arry.get(index)}" />
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{list.get(index)}" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{map[key]}" />

数据设置:

        var map = HashMap<String, Any>()
        map.put("name", "map你好")
        databind.key = "name"
        databind.map = map
        var list = ArrayList<String>()
        list.add("list0index")
        list.add("list1index")
//        databind.list = list

        var spar=SparseArray<String>()
        spar.put(0,"0 value SparseArray")
        spar.put(1,"1 value SparseArray")
        spar.put(100,"100 value SparseArray")
        databind.arry=spar
        databind.index = 100

说明:

        如果你的list没有设置,即在databind中为null,即使你设置了key或者index,也不会被引用,如果你设置了data,index会引起数组越界,但是不会抛空指针

二、databind数据介绍

        以上我们讲解的是通过系统数据取完成,但是我们在使用databinding的时候,是想使用他的数据特性,单向绑定、双向绑定。

        我们在上面介绍的数据绑定,都不涉及到,接下来我们要讲解通过databind提供的方式,进行单向绑定和双向绑定

1、单向绑定

什么叫单向绑定:

单向绑定就是data发生改变,会自动通知UI刷新,但是UI内容发生改变后,将不会引用data发生改变。

数据绑定有两种方法,第一种全家桶,第二种,用户自定义

第一种:全家桶模式BaseObservable、Bindable

BaseObservable:提供了数据更新的机制,可以通过notifyPropertyChanged(int field)和notifyChange()来完整数据的更新

Bindable:生成关联字段,形成关联图

如何使用:

1.继承:BaseObservable
2.通过Bindable注解绑定字段,改字段必须为public,否则绑定在get方法上

kotlin:

直接绑定在get方法上

class MySchool : BaseObservable() {

    @get:Bindable
    var name: String = ""
        set(value) {
            field = value
            notifyPropertyChanged(BR.name)
           

        }

}

Java:

public class MySchool extends BaseObservable {


    private String schoolName="";

    @Bindable
    public String getSchoolName() {
        return schoolName;
    }

    public void setSchoolName(String schoolName) {
        this.schoolName = schoolName;
        notifyPropertyChanged(BR.schoolName);
    }
}

关于notifyPropertyChanged()和 notifyChange()

notifyPropertyChanged:只刷新指定的字段

notifyChange:刷新对象下所有bindable的字段

注意:

        有人先写set方法,BR无法找到指定的字段,是因为该字段还没有被bindable注释绑定,生成对应的关系图,所以要先bindable,在更新,否则找不到对应的字段

字段更新监听:addOnPropertyChangedCallback

不仅可以单向绑定,我们可以坚定当前绑定的数据对应的字段:

BaseObservable提供了一个addOnPropertyChangedCallback回调,可以在这里设置字段监听
        var detail = MySchool()
        detail.addOnPropertyChangedCallback(object : Observable.OnPropertyChangedCallback(){
            override fun onPropertyChanged(sender: Observable?, propertyId: Int) {
//                TODO("Not yet implemented")

            }
        })


2.自定义绑定字段ObservableField

通过上方,我们已知道全家桶配合的使用,但是databinding也提供了基础的绑定方法ObservableField,

BaseObservableField是基础类型,可以通过该类型指定泛型,也可以通过提供的其他数据类型进行绑定

ObservableFloat
ObservableBoolean
ObservableInt
ObservableParcelable
ObservableChar
聚合数据
ObservableArrayMap
ObservableArrayList

接下来我们先从最基础的BaseObservableField基础用起

数据源:

class BaseFieldData {

    lateinit var name: ObservableField<String>
    lateinit var age: ObservableField<Int>
    lateinit var god: ObservableField<Dog>


}

class Dog() : Parcelable {

    lateinit var name: String

    lateinit var hostName: String

    constructor(parcel: Parcel) : this() {
        name = parcel.readString()!!
        hostName = parcel.readString()!!
    }

    override fun writeToParcel(parcel: Parcel, flags: Int) {
        parcel.writeString(name)
        parcel.writeString(hostName)
    }

    override fun describeContents(): Int {
        return 0
    }

    companion object CREATOR : Parcelable.Creator<Dog> {
        override fun createFromParcel(parcel: Parcel): Dog {
            return Dog(parcel)
        }

        override fun newArray(size: Int): Array<Dog?> {
            return arrayOfNulls(size)
        }
    }


}

实现:

    fun initData() {
        var name = ObservableField<String>("我的名字")
        var age = ObservableField<Int>(100)
        var dog = Dog()
        dog.name = "小黑"
        dog.hostName = name.get()!!;
        var isDog = ObservableField<Dog>(dog)
        var baseData = BaseFieldData()
        baseData.age = age
        baseData.god = isDog
        baseData.name = name
        dataBind.data = baseData


        dataBind.testClick.setOnClickListener {
            name.set("新名字")
            var newDog=Dog()
            newDog.name="我是小白"
            newDog.hostName=name.get().toString()
            isDog.set(newDog)
        }


    }

通过这样,我们已完成了担心绑定,每次我们只要更新name和age的变量值,UI会自动刷新

每个field通过set()来设置泛型参数,通过get来回去。

为什么我们没手动更新,系统确能自动完成UI的更新?

我们看下ObservableField的set()就可以知道

public void set(T value) {
    if (value != mValue) {
        mValue = value;
        notifyChange();
    }
}

当我们调用set()的时候,默认也调用的全局刷新。

第二种:采用databind封装好的

分析:

        封装好的ObservableChar已继承了BaseObservableField

public class ObservableChar extends BaseObservableField implements Parcelable, Serializable

所以只是在构造器类指定了内容类型,这样我们在使用的时候,不再需要设置泛型参数。

var size=ObservableDouble(12.0)
      <import type="androidx.databinding.ObservableDouble"/>

        <variable
            name="size"
            type="ObservableDouble" />

     <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{String.valueOf(size)}" />
       dataBind.testClick.setOnClickListener {
        
            size.set(123.2)
        }

这些都很好处理,接下我们将介绍ObservableArrayList和ObservableArrayMap

三、数据集合:

ObservableArrayList和ObservableArrayMap

 介绍一个ObservableArrayMap:

布局中的data:


        <import type="androidx.databinding.ObservableArrayMap" />

        <variable
            name="map"
            type="ObservableArrayMap&lt;String,String&gt;" />

        <variable
            name="key"
            type="String" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{map.get(key)}" />

代码中实现:

        var map = ObservableArrayMap<String, String>()
        map.put("name", "zhangshan")
        dataBind.map = map
        dataBind.key = "name"


      dataBind.testClick.setOnClickListener {
     
            map.put("name", "修改过的")
        }
 

同理,map的put方法如下:

public V put(K k, V v) {
    V val = super.put(k, v);
    notifyChange(k);
    return v;
}

也是调用了全局刷新,同理,ArryList的add方法也是这样:

介绍完以上用法,会发现,这些好像都是单向绑定,什么才是双向绑定?其实很简单

四、双向绑定

        介绍完单向绑定,其实大家已掌握了双向绑定。用周董的话说,全球音乐看话语,中文才是最屌。

双向绑定比单向绑定在view绑定的时候,多一个=号

单向:

<EditText
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="@{dbValue}" />

双向:

<EditText
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="@={dbValue}" />

这边采用了

var name = ObservableField<String>("我的名字")

进行测试。

效果图

 总结:

               只要我们掌握了单向绑定,双向绑定自然也会解决。但是,在使用双向的时候需要注意,不同的场景如果存在多处引用,会导致数据错乱。所以,在使用的时候需要格外小心。

        

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/66667.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

https服务部署指南

1.概念 https服务的证书分布如下图&#xff1a; 客户端&#xff1a;CA证书 服务器&#xff1a;服务器证书&#xff0c;服务器密钥 2.证书生成&验证 2.1 证书生成 假设我们的域名为&#xff1a; www.contoso.com 创建CA私钥 openssl ecparam -out contoso.key -name p…

JMH基准测试工具 (一):介绍

在日常开发中&#xff0c;我们对一些代码的调用或者工具的使用会存在多种选择方式&#xff0c;在不确定他们性能的时候&#xff0c;我们首先想要做的就是去测量它。大多数时候&#xff0c;我们会简单的采用多次计数的方式来测量&#xff0c;来看这个方法的总耗时。 但是&#x…

串口通信扩展知识

在Android工控系统上&#xff0c;Android与硬件的通讯交互随处可见&#xff0c;其中串口通讯是最常用的通讯方式之一。 串口通信(Serial Communication)&#xff0c; 是指外设和计算机间&#xff0c;通过数据信号线 、地线、控制线等&#xff0c;按位进行传输数据的一种通讯方式…

扩散模型(Diffusion Model)原理与代码解析(一)

一、模型概览 扩散模型的灵感来自于非平衡热力学。定义了一个扩散步骤的马尔可夫链&#xff08;当前状态只与上一时刻的状态有关&#xff09;&#xff0c;慢慢地向真实数据中添加随机噪声&#xff08;前向过程&#xff09;&#xff0c;然后学习反向扩散过程&#xff08;逆扩散…

python 图形界面“诈金花”游戏,更新了!附完整代码

旧版本的代码请见上一篇博文&#xff1a; python 从一道作业题到制作一个图形界面的“诈金花”游戏_Hann Yang的博客-CSDN博客Player1: (♥Q, ♣2, ♣8) - 单张Player2: (♦10, ♥7, ♠6) - 单张Player3: (♣4, ♠4, ♦2) - 对子Player4: (♠5, ♠9, ♥6) - 单张Player5: (♠…

SSM框架-SpringMVC(二)

目录 1 SpringMVC处理Ajax请求 1.1 RequestBody 1.2 RequestBody获取json格式的请求参数 1.3 ResponseBody 1.4、ResponseBody响应浏览器json数据 1.5 RestController注解 2 文件上传和下载 2.1 文件下载 2.2 上传文件 3 拦截器 3.1 拦截器的三个抽象方法 3.2 拦截器…

技术分享 | ClickHouse 冷热存储分离方案线上实践

作者&#xff1a;任坤 现居珠海&#xff0c;先后担任专职 Oracle 和 MySQL DBA&#xff0c;现在主要负责 MySQL、mongoDB 和 Redis 维护工作。 本文来源&#xff1a;原创投稿 *爱可生开源社区出品&#xff0c;原创内容未经授权不得随意使用&#xff0c;转载请联系小编并注明来源…

母胎级教学,工业路由器远程维护PLC详细操作指南

1、前言随着工业4.0大力推进&#xff0c;对工业现场设备的稳定性提出了更高的要求&#xff0c;大多数的设备制造商不能持续监测及管理设备&#xff0c;因为现场设备分布比较分散&#xff0c;客户不能集中管理&#xff0c;如果通过视频或电话沟通问题&#xff0c;则准确度不够&a…

【安卓学习之常见问题】jar文件中Class转java文件不准(不同软件打开的class文件不一样)

█ jar文件中Class转java文件不准 █ 系列文章目录 提示&#xff1a;这里是收集了和文件分享有关的文章 【安卓学习之常见问题】android路径及文件问题 【安卓学习之常见问题】文件分享–文件不存在 【安卓学习之常见问题】自定义组件-刷新后跳到第一行 【安卓学习之常见问题…

K_A08_005 基于 STM32等单片机驱动XY-160D模块按键控制直流电机正反转加减速启停

目录 一、资源说明 二、基本参数 四、部分代码说明 接线说明 1、STC89C52RCXY-160D模块 2、STM32F103C8T6XY-160D模块 五、基础知识学习与相关资料下载 六、视频效果展示与程序资料获取 七、项目所有材料清单 八、注意事项 九、接线表格 一、资源说明 单片机型号 测试…

【UNIAPP】APP快速免费生成一键发布页面

参考官方文档&#xff1a;https://uniapp.dcloud.net.cn/uniCloud/hosting.html# 效果预览地址&#xff1a;https://hellouniapp.dcloud.net.cn/portal 一、创建并运行uni-admin 1、创建项目 2、运行项目 3、关联到浏览器打开。 二、登录后台界面 1、进入主页面 2、如…

[附源码]Python计算机毕业设计Django校园帮平台管理系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

【2023-Pytorch-分类教程】手把手教你使用Pytorch训练自己的分类模型

之前更新过一起tf版本的训练自己的物体分类模型&#xff0c;但是很多兄弟反应tf版本的代码在GPU上无法运行&#xff0c;这个原因是tf在30系显卡上没有很好的支持。所以我们重新更新一期Pytorch版本的物体分类模型训练教程&#xff0c;在这个教程里面&#xff0c;你将会学会物体…

[附源码]计算机毕业设计面向高校活动聚AppSpringboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

【电商项目实战】新增收货地址(详细篇)

&#x1f341;博客主页&#xff1a;&#x1f449;不会压弯的小飞侠 ✨欢迎关注&#xff1a;&#x1f449;点赞&#x1f44d;收藏⭐留言✒ ✨系列专栏&#xff1a;&#x1f449;SpringBoot电商项目实战 ✨学习社区&#xff1a; &#x1f449;不会压弯的小飞侠 ✨知足上进&#x…

刷爆力扣之最短无序连续子数组

刷爆力扣之最短无序连续子数组 HELLO&#xff0c;各位看官大大好&#xff0c;我是阿呆 &#x1f648;&#x1f648;&#x1f648; 今天阿呆继续记录下力扣刷题过程&#xff0c;收录在专栏算法中 &#x1f61c;&#x1f61c;&#x1f61c; 该专栏按照不同类别标签进行刷题&…

Windows+Visual stdio+CUDA编程方式及测试

目录一、visual stdio内针对工程的配置1、新建一个空项目2、配置CUDA生成依赖项3、配置基本库目录4、配置静态链接库路径5、配置源码文件风格6、扩展文件名配置二、样例测试测试样例1样例1问题&#xff1a;找不到helper_cuda.h文件测试样例2测试样例3一、visual stdio内针对工程…

Java餐厅点餐系统uniapp源码带安装教程

一套Java开发的餐厅点餐半成品系统&#xff0c;前端使用uniapp编写&#xff0c;经过本地测试&#xff0c;这套系统还有一些功能没完善好&#xff0c;有能力的朋友可以在这套系统基础上进行二次开发。 技术架构 后端技术框架&#xff1a;springboot shiro layui 前端技术框架…

springboot项目作为静态文件服务器

springboot项目作为静态文件服务器 springboot默认文件作用 使用 spring initialzr 创建 spring boot 项目 https://start.spring.io/ static 存放静态资源 template 存放模板页面 , 例如 thymeleaf 自定义静态文件存放目录 springboot 自动装配 , 默认静态资源的目录是 s…

Flink 知识点整理及八股文问题<第一部分 Flink简介>

本篇为Flink的第一大部分&#xff0c;初识Flink&#xff0c;全篇参考自 尚硅谷2022版1.13系列 整个系列的目录如下&#xff1a; <一>Flink简介 <二>Flink快速上手 <三>Flink 部署 <四>Flink 运行时架构 <五>DataStream API <六>Flin…