赞
踩
通过前面两篇文档,我们大概了解了databinding的工作方式,view的初始化,recycleview的使用。但是这些UI都离不开数据的填充,数据的修饰。
在说到数据绑定,好多开发者平时在工作中也经常听到databinding的数据绑定有简单、单向绑定、双向绑定,玄幻莫测,不敢下手。甚至有些新手听完果然放弃。接下来我会通过代码讲解databinding的数据绑定和使用,包括map、list、和用户自定义类,让复杂的事件简单化,人人都可以掌握好并使用
数据绑定分为两种,一种是系统支持的,还有一种是databind的数据,接下来我们分梁部分介绍
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}" />
注意:一些静态方法可以在布局中直接引用,这个后期会单独介绍
聚合列的数据,在data下方也是支持的,常用的有以下三种:map、list、sparseArry。
如何使用呢?因为data下方的数据都是要指定泛型的,所以这三种数据都是支持泛型,所以你必须要指定泛型。
<variable name="list" type="ArrayList<String>" />
这里面有人会不明白<和>是什么意思,
正常格式:ArrayList<String>
databind:ArrayList<String>
所以(< 为<)左括号,(>为>)右括号
- <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<String,Object>" />
-
- <variable
- name="list"
- type="ArrayList<String>" />
-
- <variable
- name="arry"
- type="SparseArray<String>" />
-
- </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会引起数组越界,但是不会抛空指针
以上我们讲解的是通过系统数据取完成,但是我们在使用databinding的时候,是想使用他的数据特性,单向绑定、双向绑定。
我们在上面介绍的数据绑定,都不涉及到,接下来我们要讲解通过databind提供的方式,进行单向绑定和双向绑定
单向绑定就是data发生改变,会自动通知UI刷新,但是UI内容发生改变后,将不会引用data发生改变。
数据绑定有两种方法,第一种全家桶,第二种,用户自定义
第一种:全家桶模式BaseObservable、Bindable
BaseObservable:提供了数据更新的机制,可以通过notifyPropertyChanged(int field)和notifyChange()来完整数据的更新
Bindable:生成关联字段,形成关联图
1.继承:BaseObservable
2.通过Bindable注解绑定字段,改字段必须为public,否则绑定在get方法上
直接绑定在get方法上
- class MySchool : BaseObservable() {
-
- @get:Bindable
- var name: String = ""
- set(value) {
- field = value
- notifyPropertyChanged(BR.name)
-
-
- }
-
- }
- 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,在更新,否则找不到对应的字段
不仅可以单向绑定,我们可以坚定当前绑定的数据对应的字段:
BaseObservable提供了一个addOnPropertyChangedCallback回调,可以在这里设置字段监听
- var detail = MySchool()
- detail.addOnPropertyChangedCallback(object : Observable.OnPropertyChangedCallback(){
- override fun onPropertyChanged(sender: Observable?, propertyId: Int) {
- // TODO("Not yet implemented")
-
- }
- })
通过上方,我们已知道全家桶配合的使用,但是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()的时候,默认也调用的全局刷新。
封装好的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
布局中的data:
-
- <import type="androidx.databinding.ObservableArrayMap" />
-
- <variable
- name="map"
- type="ObservableArrayMap<String,String>" />
-
- <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", "修改过的")
- }
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>("我的名字")
进行测试。
只要我们掌握了单向绑定,双向绑定自然也会解决。但是,在使用双向的时候需要注意,不同的场景如果存在多处引用,会导致数据错乱。所以,在使用的时候需要格外小心。
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。