当前位置:网站首页>ViewBinding和DataBinding的理解和区别
ViewBinding和DataBinding的理解和区别
2022-07-04 12:44:00 【我的猫叫冰彬】
之前一直把ViewBinding当成了DataBinding,直到最近的学习中才发现他们不是一个东西。于是写下这篇笔记帮助理解和区分他们俩。
一、ViewBinding
1.什么是ViewBinding
先来看看官方是怎么说的。
通过视图绑定功能,您可以更轻松地编写可与视图交互的代码。在模块中启用视图绑定之后,系统会为该模块中的每个 XML 布局文件生成一个绑定类。绑定类的实例包含对在相应布局中具有 ID 的所有视图的直接引用。
在大多数情况下,视图绑定会替代
findViewById
在刚接触Android的时候,获取布局里的一个组件是通过findViewById去获取的。比如获取一个Button,那么写法就是
val btn: Button = findViewById(R.id.btn)
于是当组件很多的时候,就需要大量的用findViewById
来获取,这是很繁琐的。然后在学习郭霖老师的《第一行代码时》,郭神书里提到了kotlin-android-extensions
这个插件。该插件能够帮我们省去findViewById,在用Kotlin写的时候可以直接通过视图组件的Id来获取。
比如视图里有一个id为btn
的Button组件,那么在Acitivy中就会有一个btn变量。这个插件帮我们简化了上面的步骤。
但是这个插件很快就被Google废弃了,在AndroidStudio中引入会出现警告。
取而代之的则是ViewBinding。
而Viewbinding就是会给每一个xml布局生成一个对应的binding类。比如activity_main.xml布局,就会生成一个ActivityMainBinding类。
2.怎么使用ViewBinding
想要使用ViewBinding,首先需要在build.gradle里加入配置。
android {
...
buildFeatures {
viewBinding true
}
}
然后创建一个MainActivity,并写下布局文件activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="textView"
android:textColor="@color/black"
android:gravity="center"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn" />
</androidx.constraintlayout.widget.ConstraintLayout>
然后在Activity里的使用
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
}
}
ViewBinding帮我们生成了一个ActivityMainBinding类,我们通过ActivityMainBinding.inflate()来加载布局。
然后我们就可以通过binding来操作布局了。
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.btn.setOnClickListener {
Toast.makeText(this, "click", Toast.LENGTH_SHORT).show()
}
binding.tv.text = "setText"
}
}
这样就帮我们省去了FindViewById的步骤,这也是ViewBinding最大的功能。
二、DataBinding
1.什么是DataBinding
还是先看看官方的说法
数据绑定库是一种支持库,借助该库,您可以使用声明性格式(而非程序化地)将布局中的界面组件绑定到应用中的数据源。
这里官方的说话就有点看不懂了。那我就尝试来解释一下。
比如我们要修改一个TextView的text值,之前都是在代码里获取到TextView组件,然后通过textView.text去赋值。比如
val str = "setText"
binding.tv.text = str
或者当我们要获取一个TextView的文本值时,也需要通过textView.text来获取
val value = binding.tv.text.toString()
这样的操作就是程序化,要在逻辑代码里去赋值或取值。如果我们可以在xml布局文件里就声明该组件的值和哪个变量绑定,就能方便很多。
利用DataBinding就能做到这一点,比如
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="user" type="com.example.User"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.firstName}"/>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.lastName}"/>
</LinearLayout>
</layout>
这样声明式的方式就将数据绑定了。具体的使用方法会在下面给出。
2.怎么使用DataBinding
2.1 基础用法
想要使用DataBinding,同样需要现在build.gradle里加入配置
android {
...
buildFeatures {
dataBinding true
}
}
然后我们先创建一个User的实体类,用于绑定数据
class User(var firstName: String, var lastName: String) {}
然后写布局activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="user" type="com.example.User"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.firstName}"/>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.lastName}"/>
</LinearLayout>
</layout>
注意这里的格式, 最外层是一个Layout标签,里面包含了data标签和LinearLayout标签,这是Databinding的表示方式,LinearLayout其实就是这里的根布局。
如何形成这样的文件呢?在原本的xml文件里,将光标移动到根布局的位置,然后按alt+enter就会出现选项转换到DataBinding的格式。
然后再来分析布局文件的代码。
<data>
<variable name="user" type="com.example.User"/>
</data>
data标签里表示的是数据源,name是名称,type是类型。这里的type就是我们前面写的User实体类。
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.firstName}"/>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.lastName}"/>
</LinearLayout>
然后在TextView里的text属性,通过@{}的格式来获取data标签里声明的变量。
最后回到Activity中来绑定数据。
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding: ActivityMainBinding =
DataBindingUtil.setContentView(this, R.layout.activity_main)
binding.user = User("Test", "User")
}
}
首先是定义DataBinding时和ViewBinding有所不同,DataBinding是通过DataBindingUtil.setContentView来绑定布局的。
最后一行就是执行了数据绑定。
运行后结果如下:
这就是databinding最基础的用法。
2.2 绑定点击事件
databinding不止能绑定数据,还能绑定一些事件,比如点击事件。
我们先创建一个Handlers,里面添加一个onClick()方法,用于点击事件回调。
class Handlers {
fun myOnClick(view: View) {
Log.d("Handlers", "onClick()")
}
}
然后修改刚才的布局文件,添加一个Button组件,然后在data标签里声明刚才写的Handlers。
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="handler" type="com.example.example.Handlers" />
<variable name="user" type="com.example.example.User"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
...
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="@{handler::onClick}"
android:text="Button"/>
</LinearLayout>
</layout>
注意Button的onClick属性。依然是通过@{}来调用变量,并且对于方法的调用是"::"。
需要注意的是,自定义的这个方法的签名必须和监听器对象方法中的签名完全一样。比如点击事件是View.OnClickListner的onClick(view: View),那么自定义的方法参数也必须保持一致:myOnClick(view: View),否则会报错。
然后运行试一下,点击按钮,查看日志。
成功绑定。
2.3 使用可观察的数据对象
前面的基础使用,我们只是知道了DataBinding如何声明式而非程序式的赋值。但是这样的情况下,如果我们要修改视图里的值,我们依然需要通过在代码里赋值的方式才能修改。
数据绑定,我们更希望的是让组件属性的值直接绑定到一个变量中,当变量发生改变时组件属性的值相应发生改变,而不需要我们再去进行赋值。
那么要实现这种当一个值发生改变,另一个值相应发生改变的效果,我们很容易想到观察者模式。那我们就可以将变量变成一个可观察的数据对象。
如果去实现Observable接口的话,对于一些简单的类型来说比较麻烦。所以基础类型的变量可以用以下的类来声明
ObservableBoolean
ObservableByte
ObservableChar
ObservableShort
ObservableInt
ObservableLong
ObservableFloat
ObservableDouble
ObservableParcelable
接下来就来实践测试一下。
我们先修改一个User实体类
class User {
val firstName = ObservableField<String>()
val lastName = ObservableField<String>()
val age = ObservableInt()
}
注意这里声明变量我们使用了val,是因为要使用Observable要尽量避免开箱或封箱操作,在Java里声明也应该是pubc final属性
private static class User {
public final ObservableField<String> firstName = new ObservableField<>();
public final ObservableField<String> lastName = new ObservableField<>();
public final ObservableInt age = new ObservableInt();
}
这里有人可能会有疑问,用val定义了我怎么修改变量的值?其实Observable的实现类里都提供了get()和set()函数来修改具体的值。
接着在布局里新增一个TextView来展示age变量。
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="handler" type="com.example.example.Handlers" />
<variable name="user" type="com.example.example.User"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.firstName}"/>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.lastName}"/>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{String.valueOf(user.age)}"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="@{handler::onClick}"
android:text="Change"/>
</LinearLayout>
</layout>
然后修改一下Handlers的点击事件逻辑,点击按钮修改user的变量值。
class Handlers(private val user: User) {
fun onClick(view: View) {
user.firstName.set("Luka")
user.lastName.set("Dončić")
user.age.set(23)
Log.d("Handlers", "onClick()")
}
}
最后在MainActivity里绑定
package com.example.example
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import androidx.databinding.DataBindingUtil
import com.example.example.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding: ActivityMainBinding =
DataBindingUtil.setContentView(this, R.layout.activity_main)
val user = User()
user.firstName.set("Stephen")
user.lastName.set("Curry")
user.age.set(34)
binding.user = user
binding.handler = Handlers(user)
}
}
最终的效果如下
这样我们就不用再去给组件属性做赋值操作,只需要修改绑定的变量的值即可。
三、区别
看到这里,相信你对ViewBinding和DataBinding都有了一定的了解。接下来就总结一下他们的区别。
目的不同。ViewBinding的出现仅仅是为了帮开发人员省去写findViewById的步骤;而DataBinding是用于绑定数据的,能够把视图的数据和代码变量绑定起来,并且实现自动更新。这个特性使得DataBinding能和MVVM框架进行很好的配合。
初始化方式不同。ViewBinding通过生成的Binding类的inflate方法来加载布局,然后还需要用Activity的setContentView()方法来绑定。而Databinding则是通过DataBindingUtil.setContentView()来绑定的。
包含关系。DataBinding也有ViewBinding的功能,也可以省去findViewById()方法。
四、总结
本文从使用方面理解了什么是ViewBinding和DataBinding,并对他们做了区别分析,加深对他们俩的理解。
边栏推荐
- CVPR 2022 | transfusion: Lidar camera fusion for 3D target detection with transformer
- Scripy framework learning
- C#基础深入学习二
- 在 Apache 上配置 WebDAV 服务器
- Cann operator: using iterators to efficiently realize tensor data cutting and blocking processing
- 光环效应——谁说头上有光的就算英雄
- In 2022, it will be es2022 soon. Do you only know the new features of ES6?
- 室外LED屏幕防水吗?
- Master the use of auto analyze in data warehouse
- JVM系列——栈与堆、方法区day1-2
猜你喜欢
8 expansion sub packages! Recbole launches 2.0!
PostgreSQL 9.1 soaring Road
Master the use of auto analyze in data warehouse
It is six orders of magnitude faster than the quantum chemical method. An adiabatic artificial neural network method based on adiabatic state can accelerate the simulation of dual nitrogen benzene der
C#/VB. Net to add text / image watermarks to PDF documents
n++也不靠谱
Three schemes to improve the efficiency of MySQL deep paging query
Commvault 和 Oracle 合作,在 Oracle 云上提供 Metallic数据管理即服务
JVM系列——栈与堆、方法区day1-2
光环效应——谁说头上有光的就算英雄
随机推荐
数据库锁表?别慌,本文教你如何解决
Apache server access log access Log settings
go-zero微服务实战系列(九、极致优化秒杀性能)
提高MySQL深分页查询效率的三种方案
SQL language
Database lock table? Don't panic, this article teaches you how to solve it
光环效应——谁说头上有光的就算英雄
It is six orders of magnitude faster than the quantum chemical method. An adiabatic artificial neural network method based on adiabatic state can accelerate the simulation of dual nitrogen benzene der
面试官:Redis 过期删除策略和内存淘汰策略有什么区别?
Building intelligent gray-scale data system from 0 to 1: Taking vivo game center as an example
2022年中国移动阅读市场年度综合分析
A data person understands and deepens the domain model
WPF double slider control and forced capture of mouse event focus
. Net using redis
C foundation in-depth learning II
CommVault cooperates with Oracle to provide metallic data management as a service on Oracle cloud
[FAQ] summary of common causes and solutions of Huawei account service error 907135701
Read the BGP agreement in 6 minutes.
从0到1建设智能灰度数据体系:以vivo游戏中心为例
2022KDD预讲 | 11位一作学者带你提前解锁优秀论文