Jetpack DataBinding数据绑定
简介
DataBinding是Google提供的将视图和数据绑定的支持库,主要是为了简化代码,去除findViewById() 等样式代码的调用,借助布局文件中的绑定组件,您可以移除 Activity 中的许多界面框架调用,使其维护起来更简单、方便。还可以提高应用性能,并且有助于防止内存泄漏以及避免发生 Null 指针异常。
依赖
在app的build.gradle文件中添加依赖:
apply plugin: 'kotlin-kapt'
android {
......
//开启dataBinding
dataBinding {
enabled = true
}
}
dependencies {
......
//databinding版本跟Gradle版本一致
kapt "com.android.databinding:compiler:$gradle_version"
}
项目的build.gradle配置如下:
buildscript {
ext.kotlin_version = '1.3.50'
ext.gradle_version = '3.5.1'
repositories {
google()
jcenter()
}
dependencies {
classpath "com.android.tools.build:gradle:$gradle_version"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
Activity/Fragment中使用DataBinding
可通过在根布局上Alt+Enter(Windows下)快捷键生成绑定布局:
布局文件acitivity_main.xml代码如下:
<?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">
<data>
<import
type="com.zzs.jetpack_databinding.User"
alias="UserInfo"/>
<variable
name="user"
type="UserInfo" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
......
android:text="@{user.name}" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
注意:布局文件嵌套layout后,会生成一个binding类,类名为布局文件的名称驼峰式+Binding,如:ActivityMainBinding,如果没有找到binding类,Rebuild Project一下项目就可以了
data属性详解:
-
import:引入数据类型
type: 数据类型
alias:类型别名,防止不同路径下的相同类名重复 -
variable:变量声明
name:布局中使用的类名,如: android:text="@{user.name}"
type: 设置了别名就使用别名,否则就使用类名,如:User,
不导入数据类型(不使用import)则使用完整地址,
如: com.zzs.jetpack_databinding.User
常用数据类型引入:
<data>
<import type="android.util.SparseArray"/>
<import type="java.util.Map"/>
<import type="java.util.List"/>
<import type="com.zzs.jetpack_databinding.User"/>
<variable name="list" type="List<String>"/>
<variable name="sparse" type="SparseArray<String>"/>
<variable name="map" type="Map<String, String>"/>
<variable name="index" type="int"/>
<variable name="key" type="String"/>
<variable name="user" type="User" />
</data>
…
android:text="@{list[index]}"
…
android:text="@{sparse[index]}"
…
android:text="@{map[key]}"//没有定义key,可以android:text='@{map["name"]}'
// 或者android:text="@{map[`name`]}"
…
android:text="@{user.name}"
引用资源:
android:padding="@{large? @dimen/largePadding : @dimen/smallPadding}"
注意:要使 XML 不含语法错误,您必须转义 < 字符。例如:不要写成 List 形式,而是必须写成 List<String>。
User数据类:
data class User(
val name:String,
val age:Int
)
在Activity中代码如下:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//绑定试图
val binding = DataBindingUtil.setContentView<ActivityMainBinding>(this,R.layout.activity_main)
//绑定数据类
binding.user = User("张三",20)//User是我自己创建的数据类
}
}
在Fragment中代码如下:
class BlankFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val binding = DataBindingUtil.inflate<FragmentBlankBinding>(inflater,R.layout.fragment_blank, container, false)
return binding.root
}
}
注意:第一次没有找到DataBindingUtil类,重启一下项目就好了
处理页面点击事件:
布局文件代码:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="user"
type="com.zzs.jetpack_databinding.User" />
<variable
name="myHandles"
type="com.zzs.jetpack_databinding.MainActivity.MyHandlers" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.name}"
android:onClick="@{(view)-> myHandles.onClickUser(view,user)}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
Activity/Fragment代码:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val binding =
DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
binding.user = User("张三", 20)
//不要忘记写这个,不然点击事件无效
binding.myHandles = MyHandlers()
}
inner class MyHandlers{
fun onClickUser(view: View,user: User){
//处理点击事件逻辑
Toast.makeText(this@MainActivity, user.name, Toast.LENGTH_SHORT).show()
}
}
}
RecyclerView中使用DataBinding
RecyclerView布局文件代码:
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_user"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"/>
</layout>
item列表布局文件代码:
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="userList"
type="com.zzs.jetpack_databinding.User" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@{userList.name}"
android:padding="10dp" />
</LinearLayout>
</layout>
初始化:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val binding =
DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
val users = ArrayList<User>().apply {
for (i in 0..10) {
add(User("张三$i", 20))
}
}
binding.rvUser.layoutManager = LinearLayoutManager(this)
val adapter = UserAdapter(this, users);
binding.rvUser.adapter = adapter
//item点击事件
adapter.setOnItemClickListener(object : UserAdapter.OnItemClickListener {
override fun onItemClick(view: View, user: User) {
Toast.makeText(this@MainActivity, user.name, Toast.LENGTH_SHORT).show()
}
})
}
}
UserAdapter适配器:
class UserAdapter(private val context: Context, private val users: List<User>) :
RecyclerView.Adapter<UserAdapter.ViewHolder>() {
private lateinit var mOnClickListener: OnItemClickListener
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(
DataBindingUtil.inflate(
LayoutInflater.from(context),
R.layout.item_list_user,
parent,
false
)
)
}
override fun getItemCount(): Int {
return users.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val binding = holder.dataBinding
binding.setVariable(BR.userList, users[position])
holder.itemView.setOnClickListener {
//创建回调接口处理item点击事件
mOnClickListener.onItemClick(it, users[position])
//也可以不使用回调接口(注释上面的代码),直接在Adapter中处理点击逻辑
//todo
}
}
inner class ViewHolder(var dataBinding: ViewDataBinding) :
RecyclerView.ViewHolder(dataBinding.root)
interface OnItemClickListener {
fun onItemClick(view: View, user: User)
}
fun setOnItemClickListener(onClickListener: OnItemClickListener) {
this.mOnClickListener = onClickListener
}
}
显示: