相关文章:
Jetpack:LifeCycle全面解析(包含检测app启动、进入前台、进入后台例子)。
Jetpack:ViewModel使用指南,实现原理详细解析!
Jetpack:LiveData使用指南,实现原理详细解析!
文章目录
-
JetPack文章相关目录
-
简介
-
DataBinding简单使用
-
DataBinding响应事件
-
DataBinding二级页面的绑定
-
BindAdapter简单原理分析
-
自定义BindAdapter
-
实现双向绑定
-
自定义InverseBindingAdapter
-
InverseBindingAdapter简单分析
-
总结
=====================================================================
DataBinding可以让布局承担部分原本属于页面的工作,可以使得页面与布局文件之间的耦合程度降低。
DataBinding具有以下几点优势:
-
部分与UI相关的代码可在布局中完成,代码更简洁,可读。
-
不需要使用findViewById()方法。
-
布局文件可以包含简单的业务逻辑。
依赖:需要在模块的 build.gradle
文件中将 dataBinding
构建选项设置为 true
,如下所示:
android {
…
buildFeatures {
dataBinding true
}
}
//开启kapt
plugins {
…
id ‘kotlin-kapt’
}
注意
可以同时使用viewBinding和dataBinding,布局里面使用layout标签,则生成ViewDataBinding类型,否则生成ViewBinding类型的绑定类。
==================================================================================
-
根据
简介
的描述在build.gradle
开启dataBinding
-
修改布局文件
在布局文件最外层添加<layout>
标签作为根节点。可以手动修改添加<layout>
标签;也可以将鼠标移动到原布局跟节点位置,单击浮现的灯泡按钮,然后选择Convert to databinding layout
选项,由编译器帮忙进行转化。如下图所示:
修改完成后的布局如下所示:
<?xml version="1.0" encoding="utf-8"?><androidx.constraintlayout.widget.ConstraintLayout
android:layout_width=“match_parent”
android:layout_height=“match_parent”>
</androidx.constraintlayout.widget.ConstraintLayout>
- 实例化布局文件
常规的实例化布局文件方法通过Activity.this.setContentView()
方法实例布局文件,然后通过findViewById()
方法找到对应的UI控件并使用。使用DataBinding之后可以直接获取对应的Binding
类,然后将跟布局设置进布局文件即可;或者使用DataBindingUtil.setContentView()
方法直接设置布局文件,且该方法也会返回对应的Binding
类。
举个🌰
private var _binding: ActivityDatabindingBaseBinding? = null
val binding: ActivityDatabindingBaseBinding
get() = _binding!!
//一、直接通过Binding获取Binding类,并且设置布局
private fun initBinding() {
_binding = ActivityDatabindingBaseBinding.inflate(layoutInflater)
setContentView(binding.root)
}
//二、使用DataBindingUtil直接设置布局
private fun initBinding() {
_binding = DataBindingUtil.setContentView(this, R.layout.activity_databinding_base)
}
通过对应的Binding
类可以直接方法,布局文件声明的Id类,会将原布局文件声明的id
命名,转换为驼峰命名法。
举个🌰
//布局文件的id
<TextView
android:id=“@+id/tv_video_name”
android:layout_width=“wrap_content”
android:layout_height=“wrap_content”/>
//使用binding访问
binding.tvVideoName.text = “access ui controls through binding”
- 将数据传递到布局文件,由布局文件负责进行数据绑定
databinding
出现就希望减轻,UI曾对应数据绑定的逻辑,分层更加清晰。所以需要将数据传递到布局文件中,由布局文件负责数据的绑定。
首先声明一个实体类VideoEntity
data class VideoEntity(
val videoName: String? = “迪迦·奥特曼”,
val videoIntroduction: String? = “《迪迦·奥特曼》(ウルトラマンティガ、Ultraman Tiga),是日本圆谷株式会社拍摄的特摄电视剧。是“平成系奥特曼”系列首作,平成三部曲的首作,是奥特曼系列自1980年的 《爱迪·奥特曼》后沉寂数年迎来的重生。于1996年(平成8年)9月7日至1997年(平成9年)8月30日在JNN日本新闻网播放 [1] ,共52话。”,
val videoStarring: String? = “长野博;吉本多香美;高树零;增田由纪夫;影丸茂树;古屋畅一;川地民夫;石桥慧;二又一成”,
val videoImageUrl: String? = “https://img1.baidu.com/it/u=2288494528,306759139&fm=253&fmt=auto&app=120&f=JPEG?w=584&h=378”,
@DrawableRes val localImage: Int = R.drawable.ic_launcher_background
)
将实体类VideoEntity
传入到布局文件中,在<layout>
标签下创建<data>
标签(通过编译器直接转换databinding layout 的话,会自动生成<data>
标签),在<data>
标签下创建<variable>
标签,指定对象的路径以及对应的名称。
-
type
实体类的路径 -
name
可自定义名称
举个🌰
<?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”
xmlns:tools=“http://schemas.android.com/tools”>
<variable
name=“videoEntity”
type=“com.zxf.jetpackrelated.databinding.simpleUse.VideoEntity” />
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width=“match_parent”
android:layout_height=“match_parent”>
</androidx.constraintlayout.widget.ConstraintLayout>
在activity中,DataBinding直接生成了对应的setter方法。所以可以直接使用setVideoEntity将对象传递给布局类。如下所示:
val videoEntity = VideoEntity()
//绑定实体类
binding.videoEntity = videoEntity
- 绑定布局变量
将对象传递进去直接,就可以通过@{}
直接在布局文件中将对应的变量绑定给控件了
<TextView
android:text=“@{videoEntity.videoName}” />
<TextView
android:text=“@{videoEntity.videoIntroduction}” />
<TextView
android:text=“@{videoEntity.videoStarring}” />
在@{}
中也可以直接使用静态方法
<TextView
android:text=“@{String.valueOf(1)}” />
==================================================================================
通过Button控件,演示DataBinding如何响应onClick事件。
- 创建布局文件转为DataBinding布局
<layout 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”>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width=“wrap_content”
android:layout_height=“wrap_content”>
</androidx.constraintlayout.widget.ConstraintLayout>
- 声明一个EventHandleListener专门处理点击事件
class EventHandleListener(private val videoEntity:VideoEntity) {
fun onButtonClick1(view: View) {
Toast.makeText(context, “click1”, Toast.LENGTH_SHORT).show()
}
fun onButtonClick2(view: View) {
Toast.makeText(context, “click2”, Toast.LENGTH_SHORT).show()
}
}
- 布局中定义EventHandleListener变量,并将点击事件传递进button。通过双冒号语法
::
进行调用
<variable
name=“eventHandlerLayout”
type=“com.zxf.jetpackrelated.databinding.simpleUse.SimpleDataBindingActivity.EventHandleListener”/>
<Button
android:onClick=“@{eventHandlerLayout::onButtonClick1}”
/>
<Button
android:onClick=“@{eventHandlerLayout::onButtonClick2}”
/>
- activity中将EventHandleListener传递给布局文件
binding.eventHandler = EventHandleListener(videoEntity)
=====================================================================================
简单来说就是怎么将,数据传递到通过<include>
标签包裹的二级页面呢?
下面就将上面的按钮响应事件通过<include>
包裹一下,将EventHandleListener进行一个二级传递。
- 在一级页面定义
<include>
,将上面的按钮布局包裹进来
<include
android:id=“@+id/in_bt”
layout=“@layout/layout_databinding_base” />
- 在一级页面同样声明一下EventHandleListener变量,可以通过二级页面声明的EventHandleListener的name,将对象直接传递给二级页面
<variable
name=“eventHandler”
type=“com.zxf.jetpackrelated.databinding.simpleUse.SimpleDataBindingActivity.EventHandleListener” />
<include
android:id=“@+id/in_bt”
layout=“@layout/layout_databinding_base”
android:layout_width=“wrap_content”
android:layout_height=“wrap_content”
app:eventHandlerLayout=“@{eventHandler}”/>
====================================================================================
当启用databinding
之后,会生成大量的类,其中包括针对UI的各种命名为XXXBindAdapter的类。
截取一下TextViewBindingAdapter类的部分源码。源码展示了DataBinding库针对android:text属性所编写的代码
@BindingAdapter(“android:text”)
public static void setText(TextView view, CharSequence text) {
final CharSequence oldText = view.getText();
if (text == oldText || (text == null && oldText.length() == 0)) {
return;
}
if (text instanceof Spanned) {
if (text.equals(oldText)) {
return; // No change in the spans, so don’t set anything.
}
} else if (!haveContentsChanged(text, oldText)) {
return; // No content changes, so don’t set anything.
}
view.setText(text);
}
在布局文件中通过@{}
绑定的text,最终通过生成的BindingImpl类,调用了对应的setText静态方法。
所以总的来说,在布局文件里面绑定的数据,可以调用到BindingAdapter修饰的静态方法。
=================================================================================
仅官方提供的BindAdapter肯定是不够的,所以需要自定义BindAdapter,实现更多的更复杂的业务关系。
下面展示使用ImageView自定义BindAdapter。
- BindAdapter注解介绍
@Target(ElementType.METHOD)
public @interface BindingAdapter {
String[] value();
boolean requireAll() default true;
}
-
value
即分配给布局文件中使用的名字 -
requireAll
如果需要一下子定义多个value
,用于区别是否所有的都需要,默认为true,如果为true,则布局文件中,一旦使用了其中一个其他的也必须要声明,不然编译不通过。 -
使用glide进行图片加载
添加依赖和网络访问权限
implementation ‘com.github.bumptech.glide:glide:4.12.0’
annotationProcessor ‘com.github.bumptech.glide:compiler:4.12.0’
- 定义ImageView的BindAdapter类
需要注意的是,BindingAdapter中的方法均为静态方法。第1个参数为调用者本身,即ImageView;第2个参数是布局文件在调用该方法时传递过来的参数
对于Kotlin
来说,只需要将函数声明为顶级函数,就对应java的静态方法了。
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
学习交流
群内有许多来自一线的技术大牛,也有在小厂或外包公司奋斗的码农,我们致力打造一个平等,高质量的Android交流圈子,不一定能短期就让每个人的技术突飞猛进,但从长远来说,眼光,格局,长远发展的方向才是最重要的。
35岁中年危机大多是因为被短期的利益牵着走,过早压榨掉了价值,如果能一开始就树立一个正确的长远的职业规划。35岁后的你只会比周围的人更值钱。
一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
//img-blog.csdnimg.cn/13f2cb2e05a14868a3f0fd6ac81d625c.png)
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
[外链图片转存中…(img-YXBnFg0d-1712738793398)]
学习交流
[外链图片转存中…(img-aA55aZmR-1712738793399)]
[外链图片转存中…(img-7bWNqWJv-1712738793399)]
群内有许多来自一线的技术大牛,也有在小厂或外包公司奋斗的码农,我们致力打造一个平等,高质量的Android交流圈子,不一定能短期就让每个人的技术突飞猛进,但从长远来说,眼光,格局,长远发展的方向才是最重要的。
35岁中年危机大多是因为被短期的利益牵着走,过早压榨掉了价值,如果能一开始就树立一个正确的长远的职业规划。35岁后的你只会比周围的人更值钱。
一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-he1tUYWN-1712738793399)]