Jetpack_Data Binding 入门指南,这些新技术你们都知道吗
布局绑定
我们创建名为 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.gitcode.jetpack.User"/></data>
<LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent">//在 TextView 中使用<TextView android:layout_width="match_parent"android:gravity="center"android:text="@{user.name}"android:layout_height="match_parent"/></LinearLayout></layout>
布局文件的根元素不再是以往的 LinearLayout、RelativeLayout 等等,而是 layout。在data
元素内添加variable
,其属性表示声明一个com.gitcode.jetpack.User
类型的变量user
。如果多个变量的话,可在data
元素下添加多个varialbe
元素,格式是一致的。
<data><variable name="user" type="com.gitcode.jetpack.User"/><variable name="time" type="com.gitcode.jetpack.Time"/></data>
在@{}
语法中使用表达式将变量赋值给 view 的属性。例如:这里将 user 变量的 firstName 属性赋值给 TextView 的 text 属性。
android:text="@{user.firstName}"
绑定数据
此时布局声明的 user 变量值还是初始值,我们需要为其绑定数据。
默认情况下,会根据目前布局文件名称来生成一个绑定类(binding class),例如当前布局文件名是 activity_main,那么生成的类名就是 ActivityMainBinding。
绑定类会拥有当前布局声明变量,并声明 getter 或者 setter 方法,也就是说 ActivityMainBinding 类会带有 user 属性和 getUser、setUser 方法,变量的默认初始化与 Java 一致:引用类型为 null,int 为 0,bool 为 false。
在 MainActivity 的 onCreate()方法中添加如下代码,将数据绑定到布局上。
val binding: ActivityMainBinding= DataBindingUtil.setContentView(this, R.layout.activity_main);binding.user = User("GitCode", 3)
经典代码是这样的:
setContentView(R.layout.activity_main)val user=User("GitCode",3)val tvName=findViewById<TextView>(R.id.tvName)tvName.text = user.name
可有看出,使用数据绑定库会使代码简洁很多,可读性也很高。 运行一下项目,既可以考到效果了~
如果是在 Fragment、Adapter 中使用,那就要换个姿势了。
val listItemBinding = ListItemBinding.inflate(layoutInflater, viewGroup, false)//或者 val listItemBinding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false)
恭喜,你已经入门了
可以选择继续学习,
看下文
也可以当做了解
点个赞
看看其他文章了~
布局与绑定表达式
在一开始介绍 Data Binding Libaray 时,就使用了@{}
语法,花括号里面的内容称为绑定表达式,绑定表达式其实并不复杂,跟我们正常使用 Java 和 Kotlin 语言的表达式没多大区别。那我们可以在表达式中使用什么类型的运算符或者关键字呢?
常用运算符
其他常用的
同时也支持字符拼接+
,instanceof
,分组、属性访问、数组访问、?:
、转型、访问调用,基本类型等等等。 也就是说,绑定表达式语言大多数跟宿主代码(Java or Kotlin)的表达式差不多。为什么说是大多数,因为不能使用this
、super
、new
和Explicit generic invocation
(明确的泛型调用)等。
丢个栗子:
android:text="@{String.valueOf(index + 1)}"android:visibility="@{age > 13 ? View.GONE : View.VISIBLE}"android:transitionName='@{"image_" + id}'
再举丢个栗子:
android:text="@{user.displayName ?? user.lastName}"
如果user.displayName
不为 null 则使用,否则使用user.lastName
.在这里也看得出,可以通过表达式访问类的属性。绑定类会自动检查当前变量是否为 null,以避免发生空指针异常。栗子:如果user
变量为 null,那么user.lastName
也会是 null。
集合
像数组,链表,Maps 等常见的集合,都可以采用下标[]
访问它们的元素。
<data><import type="android.util.SparseArray"/><import type="java.util.Map"/><import type="java.util.List"/><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"/></data>…android:text="@{list[index]}"…android:text="@{sparse[index]}"…android:text="@{map[key]}"//或者 android:text="@{map.key}"
注意在data
元素内添加了import
元素,表示导入该类型的定义,这样表达式中引用属性可读性高点,使用也方便。
来个容易掰的栗子:
<data><import type="android.view.View"/></data>
<TextViewandroid:text="@{user.lastName}"android:layout_width="wrap_content"android:layout_height="wrap_content"android:visibility="@{user.isAdult ? View.VISIBLE : View.GONE}"/>
通过导入 View 类型,就可以使用相关属性,例如这里的View.VISIBLE
。
有时导入的类全名太长了或者存在相同类型的类名,我们就可以给它取个别名,然后就可用别名进行 coding~
<import type="android.view.View"/>
<import type="com.gitcode.jetpack.View"alias="JView"/>
使用资源
使用下面语法:
android:padding="@{@dimen/largePadding}"
相关资源的的表达式引用,贴张官网截图:
事件处理
数据绑定库允许我们在事件到 View 时候通过表达式去处理它。 在数据绑定库中支持两种机制:方法调用和监听器绑定。
好想一笔带过,因为原文看不明白~~~~(>_<)~~~~
方法调用
点击事件会直接绑定到处理方法上,当一个事件发生,会直接传给绑定的方法。类似我们在布局上使用android:onclick
与 Activity 的方法绑定。在编译的时候已经绑定,在@{}
表达式中的方法如果在 Activity 找不到或者方法名错误,就会在编译时期报错,方法签名(返回类型和参数相同)一致。
丢个栗子:
定义一个接口,用于处理事件。
//定义一个处理点击事件的类 interface MethodHandler {fun onClick(view: View)}
在布局声明了 methodHandler 变量,并在 Button 的onClick
方法使用表达式@{methodHandler::onClick}
,onClick
方法需要与上面接口一致,不然编译器期报错。
<?xml version="1.0" encoding="utf-8"?><layout xmlns:android="http://schemas.android.com/apk/res/android"><data>...<variable name="methodHandler"type="com.gitcode.jetpack.MethodHandler"/></data>
<LinearLayoutandroid:layout_width="match_parent"android:orientation="vertical"android:gravity="center_horizontal"android:layout_height="match_parent">...<Button android:layout_width="wrap_content"android:text="Method references"android:layout_marginTop="10dp"android:onClick="@{methodHandler::onClick}"android:layout_height="wrap_content"/></LinearLayout></layout>
然后在 Activity 中实现 MethodHandler,并赋值给绑定类的变量。
class MainActivity : AppCompatActivity(), MethodHandler{lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {...binding.methodHandler = this}
override fun onClick(view: View) {Log.i(TAG, "Method handling")}}
因此,当我们点击 Button 的时候,Activity 的 onClick 方法就会被回调。
监听器绑定
监听器绑定与方法调用不同的是,监听器不再编译器与处理方法绑定,而是在点击事件传递到当前 view 时,才与处理方法绑定,而且监听器并不要表达式方法名与处理方法同名,只要返回类型一致即可,如果有返回值得话。
来个栗子:
定义接口用于处理事件
interface ListenerHandler {fun onClickListener(view: View)}
在布局中定义变量和表达式
<?xml version="1.0" encoding="utf-8"?><layout xmlns:android="http://schemas.android.com/apk/res/android"><data><variable name="listener" type="com.gitcode.jetpack.ListenerHandler"/></data>
<Button android:layout_width="wrap_content"android:text="Listener"android:layout_marginTop="10dp"android:onClick="@{(view)->listener.onClickListener(view)}"android:layout_height="wrap_content"/></LinearLayout><layout>
注意到使用 lambda 表达式,因此可以在@{}
内做更多操作,如预处理数据等。
处理方法 同样在 Activity 实现 ListenerHandler 方法,并赋值给绑定类的变量。
class MainActivity : AppCompatActivity(), ListenerHandler {lateinit var binding: ActivityMainBinding
override fun onClickListener(view: View) {Log.i(TAG, "Listener handling")}
override fun onCreate(savedInstanceState: Bundle?) {...binding.listener=this}}
点击 Button,就能看到 onClickListener 回调了~
不过瘾的,看[官网](
)吧
好了,讲到这里,大家喝杯奶茶续命,休息会吧~
吃完瓜了没?吃完了就该继续撸文了,毕竟革命尚未成功~
绑定类
前面讲的大多数是在布局中去使用表达式,从这开始,讲点代码中的操作。在一开始入门时候,讲到会根据当前布局生成绑定类,绑定类类名由布局名称根据 Pascal 规则和添加 Binding 后缀生成。举个栗子就明白了,当前布局名称:activity_shared.xml。生成绑定类名称:ActivitySharedBinding。
那么绑定类的作用是什么?
绑定类是数据绑定库为让我们可以访问布局中的变量和视图而生成的类。
如何创建或者定制绑定类呢?
创建绑定类
使用静态 inflate()方法
ActivityMainBinding.inflate(LayoutInflater.from(this))
重载版本
ActivityMainBinding.inflate(getLayoutInflater(), viewGroup, false)
使用静态 bind()方法
//一般这种情况是布局有作其他用途 ActivityMainBinding.bind(viewRoot)
在 Fragment,ListView,或 RecyclerView 的 adapter 使用
val listItemBinding = ListItemBinding.inflate(layoutInflater,viewGroup, false)
评论