DataBinding的进阶用法的演示:
1、响应式user对象的演示
2、list、recyclerView的演示使用
3、kotlin中binding的写法的优势
1. 布局文件
1.1 activity_common_use.xml
- <layout xmlns:app="http://schemas.android.com/apk/res-auto"
- xmlns:tools="http://schemas.android.com/tools">
-
- <data>
-
- <variable
- name="user"
- type="org.hanyang.jetpack.binding.bean.CommonUser" />
-
- <variable
- name="fuser"
- type="org.hanyang.jetpack.binding.bean.FieldUser" />
-
- <variable
- name="ouser"
- type="org.hanyang.jetpack.binding.bean.ObUser" />
-
- <import type="android.view.View" />
-
-
- <variable
- name="show"
- type="Boolean" />
-
- <variable
- name="ladapter"
- type="org.hanyang.jetpack.binding.adapter.LAdapter" />
-
- <variable
- name="radapter"
- type="org.hanyang.jetpack.binding.adapter.RAdapter" />
- data>
-
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:padding="10dp">
-
-
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/tv_common_user_info"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:text="@{user.name + user.age + user.sex + user.desc}"
- tools:text="普通user的数据信息" />
-
- <androidx.appcompat.widget.AppCompatButton
- android:id="@+id/btn_change_common"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="普通改变"
- android:textAllCaps="false" />
-
-
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/tv_field_user_info"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:text="@{fuser.name+fuser.age+fuser.sex+fuser.desc}"
- android:textColor="@android:color/holo_blue_light"
- tools:text="Field的user的数据信息" />
-
- <androidx.appcompat.widget.AppCompatButton
- android:id="@+id/btn_change_field"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="改变Field"
- android:textAllCaps="false" />
-
-
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/tv_ob_user_info"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:text="@{ouser.toString()}"
- android:textColor="@android:color/holo_green_dark"
- tools:text="Observable user的数据信息" />
-
- <androidx.appcompat.widget.AppCompatButton
- android:id="@+id/btn_change_ob"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="改变Observable"
- android:textAllCaps="false" />
-
-
- <androidx.appcompat.widget.AppCompatTextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="这是一个显示/隐藏文案,根据checkbox的状态"
- android:visibility="@{show?View.VISIBLE:View.INVISIBLE}" />
-
- <androidx.appcompat.widget.AppCompatCheckBox
- android:id="@+id/cb_common"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="控制显示文案" />
-
-
- <include
- layout="@layout/layout_user"
- ouser="@{ouser}" />
-
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="horizontal">
-
- <ListView
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- app:adapter="@{ladapter}"
- tools:listitem="@layout/item_lv" />
-
-
- <androidx.recyclerview.widget.RecyclerView
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- app:adapter="@{radapter}"
- app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
- tools:listitem="@layout/item_lv" />
- LinearLayout>
- LinearLayout>
- layout>
1.2 layout_user.xml
- <layout>
-
- <data>
- <variable
- name="ouser"
- type="org.hanyang.jetpack.binding.bean.ObUser" />
- data>
-
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <androidx.appcompat.widget.AppCompatTextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@{ouser.toString()}" />
- LinearLayout>
- layout>
1.3 item_lv.xml
- <layout xmlns:tools="http://schemas.android.com/tools">
-
- <data>
-
- <variable
- name="user"
- type="org.hanyang.jetpack.binding.bean.ObUser" />
- data>
-
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="1dp"
- android:orientation="horizontal"
- android:padding="5dp">
-
- <androidx.appcompat.widget.AppCompatTextView
- android:layout_width="30dp"
- android:layout_height="wrap_content"
- android:background="@android:color/holo_purple"
- android:gravity="center"
- android:text="@{user.name}"
- tools:text="姓名" />
-
-
- <androidx.appcompat.widget.AppCompatTextView
- android:layout_width="30dp"
- android:layout_height="wrap_content"
- android:background="@android:color/holo_orange_light"
- android:gravity="center"
- android:text="@{user.age+``}"
- tools:text="年龄" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:layout_width="30dp"
- android:layout_height="wrap_content"
- android:background="@android:color/holo_blue_dark"
- android:gravity="center"
- android:text="@{user.sex +``}"
- tools:text="性别" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:background="@android:color/holo_green_light"
- android:gravity="center"
- android:text="@{user.desc}"
- tools:text="简述" />
- LinearLayout>
- layout>
2. 模型bean文件 User.kt
- /**
- * ----------------------------------------------------------------
- * 用于DataBinding的数据对象类,user,这里在kotlin中,多个public的class可以放在一个kt文件中
- */
-
- /**
- * 普通的数据类,这里用了kotlin的数据类 data class 也就是一个特殊的class而已。
- * val 表示不可变量,var 可变。这些在kotlin的代码演示中会有描述
- */
- data class CommonUser(
- val name: String, //姓名
- var age: Int, //年龄
- var sex: Int, //性别 0 女 1 男
- var desc: String //描述
- )
-
- /**
- * 这是部分属性可以databinding响应的user类,注意observable的属性需要public权限,否则dataBinding则无法通过反射处理数据响应
- */
- data class FieldUser(
- var name: String, //姓名
- var age: ObservableInt,//可响应的Int类型
- var sex: Int,
- var desc: ObservableField
//可响应的String类型 - )
-
- /**
- * 继承dataBinding的baseObservable的user对象类
- * 这里是kotlin的写法,类似于java中,继承BaseObservable的对象类,
- * 需要响应变化的字段,就在对应变量的get函数上加 @Bindable 。然后set中notifyChange kotlin的写法,免去了java的getter setter的方式
- * 成员属性需要响应变化的,就在其set函数中,notify一下属性变化,那么set的时候,databinding就会感知到。
- */
- class ObUser() : BaseObservable() {
-
- //kotlin中类的构造函数可以多个,有主次之分,且次级构造函数必须调用主构造函数,如这里的this()
- constructor(name: String, age: Int, sex: Int, desc: String) : this() {
- this.name = name
- this.age = age
- // this.sex = sex
- this.desc = desc
- }
-
- //这是单独在set上@bindable,name可以声明private
- var name: String = ""
- //kotlin的成员属性必须初始化(或者lateinit)
- set(value) {
- //BR.name表示通知name这个属性的变化。 notifyChange() 通知所有变化
- notifyPropertyChanged(BR.name)
- field = value
- }
- @Bindable
- get() = field
-
- //这是在整个变量上声明@bindable,所以必须是public的
- @Bindable
- var age = 18
- set(value) {
- notifyPropertyChanged(BR.age)
- field = value
- }
- get() = field
-
- val sex = 1
-
- var desc: String = ""
- set(value) {
- field = "$value\n set中多余的拼接"//描述
- notifyPropertyChanged(BR.desc)
- }
- @Bindable
- get() = field
-
- override fun toString(): String {
- notifyChange()
- return "ObUser(name='$name', age=$age, sex=$sex, desc='$desc')"
- }
- }
3. 适配器文件
3.1 LAdapter.kt
- /**
- * ListView的adapter,简单演示,所以也不写viewHolder了
- */
- class LAdapter : BaseAdapter() {
- private var users: MutableList
= arrayListOf() -
- init {
- //初始化三个数据
- for (i in 0..2) {
- users.add(ObUser("小小$i", 20 + i, i % 2, "小小的说明 $i"))
- }
- }
-
- override fun getCount(): Int {
- return users.size
- }
-
- override fun getItem(position: Int): ObUser {
- return users[position]
- }
-
- override fun getItemId(position: Int): Long {
- return position.toLong()
- }
-
- //简单演示,就不用 viewHolder,实际请使用
- override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
- val inflater = LayoutInflater.from(parent?.context)
- var binding = ItemLvBinding.inflate(inflater)
- // Java 写法
- // if (convertView == null) {
- // binding = DataBindingUtil.inflate
(inflater, R.layout.item_lv, parent, false) - // } else {
- // binding = DataBindingUtil.getBinding
(convertView)!! - // }
- // binding.setVariable(BR.user, users.get(position))
- binding.user = users[position]
- return binding.root
- }
- }
3.2 RAdapter.kt
- /**
- * 简单演示的RecyclerView的adapter
- */
- class RAdapter : Adapter<RAdapter.MyHolder>() {
- private var users: MutableList
= arrayListOf() -
- init {
- //初始化三个数据
- for (i in 0..2) {
- users.add(ObUser("小艾 $i", 20 + i, i % 2, "小艾的说明 $i"))
- }
- }
-
- override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyHolder {
- val inflater = LayoutInflater.from(parent.context)
- val binding = ItemLvBinding.inflate(inflater)
- return MyHolder(binding)
- }
-
- override fun onBindViewHolder(holder: MyHolder, position: Int) {
- //java 写法可以setVariable
- holder.binding.user = users[position]
- holder.binding.executePendingBindings()
- }
-
- //kotlin,return的方式,可以简写
- override fun getItemCount() = users.size
-
- //在构造函数中声明binding变量,这样上面的holder才能引用到,如果不加val/var,就引用不到,就需要在class的{}内写get函数
- class MyHolder(val binding: ItemLvBinding) : ViewHolder(binding.root)
- }
4. 测试页面 CommonUseActivity.kt
- /**
- * DataBinding的进阶用法的演示界面
- * 1、响应式user对象的演示
- * 2、list、recyclerView的演示使用
- * 3、kotlin中binding的写法的优势
- */
- class CommonUseActivity : AppCompatActivity(), View.OnClickListener {
-
- //一种懒加载的初始化控件的方式
- private val tvCommon: AppCompatTextView by lazy { findViewById
(R.id.tv_common_user_info) } -
- //这里由于使用了 apply plugin: 'org.jetbrains.kotlin.android.extensions' 会自动将xml中的id,关联为控件(也可以在代码中直接用tv_field_user_info)
- private val tvField: AppCompatTextView by lazy { tv_field_user_info }
-
- //这是稍后初始化的方式
- private lateinit var tvObservable: AppCompatTextView
-
- private lateinit var user: CommonUser //普通user对象
- private lateinit var fuser: FieldUser //部分属性可变的user
- private lateinit var obUser: ObUser //BaseObservable 的user
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- //关联布局,binding 对象
- val binding = DataBindingUtil.setContentView
( - this,
- R.layout.activity_common_use
- )
- //初始化user,fuser,obuser的对象,并赋值到binding中去
- user = CommonUser("张三", 31, 1, "排行第三")
- binding.user = user
- //普通点类似java点方式,关联控件和注册事件
- binding.btnChangeCommon.setOnClickListener(this)
-
- //ObservableInt(
- fuser = FieldUser("李四", ObservableInt(20), 0, ObservableField
("李四名字的由来")) - //在代码中要获取desc这样的observable的属性,就需要用get(),而且get()的是可null的返回,
- //xml中直接用 user.desc即可,不需要写 .get(). 写了也无妨
- //fuser.desc.get()
- binding.fuser = fuser
- binding.btnChangeField.setOnClickListener(this)
-
- obUser = ObUser("王二", 22, 0, " 性别是改不了的,因为内部val声明了不可变量")
- binding.ouser = obUser
- //lateinit 延迟初始化
- tvObservable = tv_ob_user_info
- binding.btnChangeOb.setOnClickListener(this)
-
- //checkbox的响应
- cb_common.setOnCheckedChangeListener { compoundButton, checked ->
- //设置变量
- binding.show = checked
- }
-
- //adapter 设置
- binding.ladapter = LAdapter()
- binding.radapter = RAdapter()
- }
-
- //点击事件点处理
- override fun onClick(view: View?) {
- when (view?.id) {
- R.id.btn_change_common -> {
- user.age = 10; user.desc = "张三的改变desc,普通user对象不会影响binding"
- Toast.makeText(this, "注意上面的common user的info信息不会变化", Toast.LENGTH_SHORT).show()
- //当然,如果在此处,显示的代码设置Text,会变化,但是这不是数据绑定,因为你每次改变都要setText才生效
- //tvCommon.text = user.desc
- }
- R.id.btn_change_field -> {
- //fuser.name = "李四/李斯 "
- fuser.age.set(23)
- //值都会被改变
- fuser.desc.set("这两个field可以改变,你会发现名字的name是不会改变的")
- }
- R.id.btn_change_ob -> {
- obUser.name = "王二二"
- obUser.age = 222
- obUser.desc = "王二的名字,年龄,描述都会响应binding的变化"
- }
- }
- }
- }
5. 效果图
