Android DataBinding从入门到精通

DataBinding可以更加方便的编写与视图交互的代码。即系统会为模块中的每个xml文件生成一个绑定类,其实例包含指向相应布局中具有ID的所有视图的直接引用。大多数情况下,DataBinding会代替findMyId。

启动DataBinding

在Android SDK 32及后续版本中(PCCT控制面板用的版本为SDK 34),在项目gradle中配置:

adroid {compileSdk 32buildFeatures {viewBinding true}
}

然后,系统会将XML(layout)文件的名称转换为驼峰式,并在末尾添加“Binding”作为词缀。即若xml的文件名称为ActDataBindg1,那么会自动生成ActDataBinding1Binding类,可以直接使用。

Java调用

在DataBindingAct1中,需要调用setContentView

public class DataBindingAct1 extends AbsActivity {ActDataBinding1Binding binding;@Overrideprotected void onCreate(Bundle savedInstantceState){super.onCreate(savedInstanceState);binding = ActDataBinding1Binding.inflate(getLayoutInflater());setContentView(binding.getRoot());binding.tv1.setText("可以直接使用TextView");binding.tv2.setText("不用findViewById");}
}

可以看出,不像过去的方式,不用写那么多冗余的findViewById,可以直接使用binding。同时,每个类还绑定一个getRoot()方法用于为相应布局文件的根视图提供引用。

DataBindingUtil

在上文的ActDataBinding1Binding.inflate(getLaoutInflater())也可以用于换为DataBindingUtil.setContentView,如下所示:

@Override
protected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);binding = DataBindingUtil.setContentView(this, R.layout.act_data_binding_1);
}

Binding与findViewById的区别:

与使用findViewById相比,将视图绑定有如下优点:

  • Null安全:由于视图绑定创建了对视图的直接引用,因此不会出现因视图无效ID而出现Null异常。同时,若视图只出现在布局的某些配置中,那么绑定类中的引用字段会加@Nullable注解。
  • 类型安全:每个绑定类中的字段均有与之匹配的类型(XML文件中引用的视图)。这意味着不会发生类转换异常的问题。

Activity示例

首先提供一个抽象类BaseAct封装一些常用操作,继承ViewDataBinding

/*** 抽象类*/public abstract class BaseAct<B extends ViewDataBinding> extends AppCompatActivity {protected B binding;// @return 界面对应的layout idprotected abstract int getLayoutId();@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(saveInstanceState);binding = DataBindingUtil.setContentView(this, getLayoutId());}}

实现类继承BaseAct,指定ViewDataBinding的子类后,就可以使用binding对象了。

public class MainActivity extends BaseAct<ActMainBinding> {@Overrideprotected int getLayoutId() {return R.layout.act_main;}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// binding操作}@Overridepublic void onBackPressed() {}
}

使用Observable

DataBinding提供Obeservable接口用于监听实体类对象属性的变化,其具有添加、删除监听的功能。

我们可以直接实现基本监听类BaseObeservable,然后在get方法加上@Bindable注解,set方法中直接调用notifyPropertyChanged通知UI更新即可。

继承BaseObservable类

设计一个类SysInfo(代表业务上的数据),并让它集成BaseObservable类,给Get方法加@Bindable注解

public class SysInfo {private String info1 = build.MANUFACTURER;private String timeStr = " ";private long time;@Bindablepublic String getInfo1() return info1;}public void setTimeStr(String timeStr) {this.timeStr = timeStr;notifyPropertyChanged(BR.timeStr);}@Bindablepublic long getTime() {return time;}public void setTime(long time) {this.time = time;notifyPropertyChanged(BR.time);}
}

此时,SysInfo类就是可以被观测到的了。其中在set方法中调用notifyPropertyChanged()、get方法上加@Bindable注解,在编译工程后,DataBinding就会在BR文件中生成相应字段。【BR是编译期间生成的类,相当于R文件】

接下来,定义工具类DataUtils的,提供静态方法【后续会在layout中用到】

public class DataUtils {private static SimpleDateFormat format =  new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);public static String formatTime(long time) {return format.format(time);}
}

layout布局

在data标签下使用多个import标签把使用的类导入。

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"><data>// 引入[import]工具类DataUtils<import type="com.rustfisher.tutorial2020.databinding.DataUtils" />// 生命[variable]使用SysInfo对象。变量名为info<variablename="info"type="com.rustfisher.tutorial2020.databinding.data.SysInfo" /></data><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:padding="16dp">// 使用DataUtils方法,也是@{}<TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{info.info1}" /><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{info.timeStr}" />// 在使用对象的属性时,也可以直接进行操作<TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{DataUtils.formatTime(info.time)}" /></LinearLayout>
</layout>

Activity代码

在layout文件中设置了SysInfo变量后,binding会自动生成binding.setInfo()方法。

在Activity中创建一个SysInfo对象,交由binding。后续这个对象的数据变化时,界面即可相应改变。为演示数据变化,使用定时器更新数据。

public class DataBindingAct1 extends AbsActivity {private ActDataBinding1Binding binding;private SysInfo mSysInfo = new SysInfo();private Timer mTimer;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);binding = DataBindingUtil.setContentView(this, R.layout.act_data_binding_1);binding.setInfo(mSysInfo);mTimer = new Timer();// 定期执行,每500毫秒执行一次[0 表示0延迟,500 表示周期时间]mTimer.schedule(new TimerTask() {@Overridepublic void run() {mSysInfo.setTimeStr("Time: " + System.currentTimeMillis());mSysInfo.setTime(System.currentTimeMillis());}}, 0, 500);}@Overrideprotected void onDestroy() {super.onDestroy();mTimer.cancel();}
}

可观察数据对象ObservableField

对于基础类型使用如下类型即可:

ObservableBoolean
ObservableByte
ObservableChar
ObservableShort
ObservableInt
ObservableLong
ObservableFloat
ObservableDouble
ObservableParcelable

对于自创建对象,使用可观察字段避免访问操作期间封箱和开箱的操作,使用此机制需要使用public final属性:

User.java
import androidx.databinding.ObservableField;
import androidx.databinding.ObservableInt;public class User {public final ObservableField<String> firstName = new ObservableField<>();public final ObservableField<String> lastName = new ObservableField<>();public final ObservableInt age = new ObservableInt();
}// 要访问字段值,使用set()和get()方法
user.firstName.set("Google");
int age = user.age.get();

使用ObservableField

在使用Observable时,在每个set方法都需要调用notifyPropertyChanged去通知ui,而在ObservableField即可避免这个事情:

public class SysInfoObs {public ObservableField<String> info1 = new ObservableField<>(Build.MANUFACTURER);public ObservableField<String> timeStr = new ObservableField<>();public ObservableField<Long> time = new ObservableField<>();
}

layout与上文大致相同,只需将variable改为新建的SysInfoObs类:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"><data><import type="com.rustfisher.tutorial2020.databinding.DataUtils" />// 将variable改为新建的SysInfoObs类<variablename="info"type="com.rustfisher.tutorial2020.databinding.data.SysInfoObs" /></data><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:padding="16dp"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{info.info1}" /><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{info.timeStr}" /><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{DataUtils.formatTime(info.time)}" /></LinearLayout>
</layout>

在Activity中更改使用方式,新建DataBindingAct2类,持有SysInfoObs的对象:

public class DataBindingAct2 extends AbsActivity {private ActDataBinding2Binding binding;private SysInfoObs mSysInfo = new SysInfoObs();private Timer mTimer;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);binding = DataBindingUtil.setContenteView(this, R.layout.act_data_binding_2);binidng.setInfo(mSysInfo);mTimer = new Timer();mTimer.schedule(new TimerTask() {@Overridepublic void run() {mSysInfo.timeStr.set("Time: " + System.currentTimeMillis());mSysInfo.time.set(System.currentTimeMillis());}}, 0, 500);}@Overrideprotected void onDestroy() {super.onDestroy();mTimer.cancel();}
}

在更新数据时,使用ObservableField的set方法即可。

可观察集合

某些应用使用动态结构存储数据,当键为引用时,ObservableArrayMap则非常有用:

ObservableArrayMap<String, Object> user = new ObservableArrayMap<>();
user.put("firstName", "RUST");
user.put("lastName", "Fisher");
user.put("age", 18);
binding.setUser(user);

layout文件如下:

<data><import type="androidx.databinding.ObservableArrayMap" />// 注意Map的左尖括号要使用&lt<variablename="user"type="ObservableArrayMap&lt;String, Object>" />
</data><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text='@{user.firstName + " " + user.lastName}' /><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{String.valueOf(1 + (Integer)user.age)}" />

使用ObservableArraylist如下所示:

ObservableArrayList<Object> obList = new ObservableArrayList<>();
obList.add("NeoSoft");
obList.add("Java");
obList.add("Android");
obList.add(2020);
binding.setObList(obList);

在layout中设置

<data><import type="androidx.databinding.ObservableArrayList" /><variablename="obList"type="ObservableArrayList&lt;Object>" />
</data><!-- .... --><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text='@{obList[0] + " " + obList[1]}' /><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text='@{String.valueOf(1 + (Integer)obList[3])}' />

点击事件

准备监听方法,以MutableDemoVm类为例

public class MutableDemoVM {// ... // 用于设置点击监听public void onClickBack(View view) {// ...}// 用于设置点击监听public void onClickAdd(View view) {// ...}
}

其中需要View作为参数,因为要对应View.OnClickListener的onClick(View v)方法

public interface OnClickListener {/*** Called when a view has been clicked.** @param v The view that was clicked.*/void onClick(View v);
}

layout中设置监听方法

设置android:onClick监听

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"><data><variablename="vm"type="com.rustfisher.tutorial2020.databinding.data.MutableDemoVM" /></data><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="50dp"android:orientation="horizontal"><ImageViewandroid:layout_width="50dp"android:layout_height="50dp"android:onClick="@{vm.onClickBack}"android:padding="10dp"android:src="@drawable/ic_arrow_back_black_24dp" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical">// 设置android:onClick时,建议用2个冒号@{vm::onClickAdd}来引用方法都可以// 随着Jetpack的升级,后面只用2个冒号的形式<Buttonandroid:layout_width="100dp"android:layout_height="50dp"android:layout_gravity="center_horizontal"android:layout_marginTop="20dp"android:onClick="@{vm::onClickAdd}"android:text="+" /></LinearLayout></LinearLayout>
</layout>

在activity中设置数据

public class MutableDemo1 extends AppCompatActivity {private ActMutableDemo1Binding binding;private MutableDemoVM mVM = new MutableDemoVm();@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);binding = DataBindingUtil.setContentView(this, R.layout.act_mutable_demo1);binding.setVm(mVM);// ...}
}

RadioButton OnCheckedChangeListener

在类中定义好选择的方法,方法签名和CompoundButton.OnCheckedChangeListener.onCheckedChanged(CompoundButton buttonView, boolean isChecked)一致。

public void choose1(CompoundButton buttonView, boolean isChecked) {// ...
}public void choose2(CompoundButton buttonView, boolean isChecked) {// ...
}

在layout中设置使用方法。

<RadioGroupandroid:layout_width="wrap_content"android:layout_height="wrap_content"><RadioButtonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:onCheckedChanged="@{viewModel.choose1}"android:text="选项1"/><RadioButtonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:onCheckedChanged="@{viewModel.choose2}"android:text="选项2" />
</RadioGroup>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/49134.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如祺出行大跌:现在谈Robotaxi概念股是不是太早了?

文&#xff1a;互联网江湖 作者&#xff1a;刘致呈 有人说Robotaxi就像当年汽车换马车&#xff0c;是生产力的进步&#xff0c;是历史的更迭。 真的如此吗&#xff1f; 人们有疑问&#xff0c;市场也有疑问。 你看市面上主打Robotaxi概念的企业&#xff0c;有几家是持续向好…

MATLAB基础:字符串、元胞数组

今天我们继续学习MATLAB中的字符串、元胞和结构 字符串 由于MATLAB是面向矩阵的&#xff0c;所以字符串的处理可以用矩阵的形式实现 字符串的赋值与引用 假设变量a&#xff0c;将用单引号引起来的字符串赋值给它&#xff0c; a清心明目, b(a[4;-1;1]) 在这里&#xff0c;…

如何检查我的网站是否支持HTTPS

HTTPS是一种用于安全通信的协议&#xff0c;是HTTP的安全版本。HTTPS的主要作用在于为互联网上的数据传输提供安全性和隐私保护。通常是需要在网站安装部署SSL证书来实现网络数据加密传输&#xff0c;安全加密功能。 那么如果要检查你的网站是否支持HTTPS&#xff0c;可以看下…

云计算实训11——web服务器的搭建、nfs服务器的搭建、备份静态文件、基于linux和windows实现文件共享

一、搭建web服务器 1.关闭firewall和selinux 关闭防火墙 systemctl stop firewalld systemctl disable firewalld 停用selinux setenforce 0 配置文件中让sellinux不再启动 vim /etc/selinux/config SELINUXpermissive 2.编辑dns配置文件 vim /etc/resolv.conf nameserver 114.…

Go基础编程 - 11 - 函数(func)

接口&#xff08;interface&#xff09; 函数1. 函数定义1.1. 函数名1.2. 参数列表1.3. 返回值列表 2. 匿名函数3. 闭包、递归3.1 闭包3.1.1 函数、引用环境3.1.2 闭包的延迟绑定3.1.3 goroutine 的延迟绑定 3.2 递归函数 4. 延迟调用&#xff08;defer&#xff09;4.1 defer特…

个性化IT服务探索实践

探索和实践个性化IT服务,可以为用户提供更优质、定制化的解决方案,从而提升用户体验和满意度。以下是一些具体的步骤和建议,帮助自己在未来探索和实践个性化IT服务。 一、了解用户需求 用户调研和反馈: 进行用户调研,了解用户的需求和痛点。收集用户反馈,通过问卷、采访…

逆向破解 对汇编的 简单思考

逆向破解汇编非常之简单 只是一些反逆向技术非常让人难受 但网络里都有方法破解 申请变量 &#xff1a; int a 0; 00007FF645D617FB mov dword ptr [a],0 char b b; 00007FF645D61802 mov byte ptr [b],62h double c 0.345; 00007FF645D61…

2024-07-22 Unity AI行为树1 —— 框架介绍

文章目录 1 行为树2 行为树驱动方式3 行为树结点分类3.1 控制节点3.2 执行节点 4 行为树与状态机比较 本文章参考 B 站唐老狮 2023年直播内容。 点击前往唐老狮 B 站主页。 1 行为树 ​ 行为树&#xff08;Behavior Tree&#xff0c;BT&#xff09;在游戏 AI 中是一种用于控制…

微软蓝屏事件:网络安全与系统稳定性的反思与前瞻

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

探索深度学习在图像识别领域的创新应用

摘要&#xff1a; 本文深入探讨了深度学习在图像识别领域的最新进展和创新应用。通过对卷积神经网络&#xff08;CNN&#xff09;等模型的研究&#xff0c;分析了其在人脸识别、物体检测和场景理解等方面的卓越表现&#xff0c;并展望了未来深度学习技术在图像识别领域的发展趋…

javascript 的执行上下文与作用域

目录 1. 初步了解 上下文&#xff08;context&#xff09;2. 全局上下文(global context)3. 上下文栈 (context stack)4. 作用域链( scope chain)5. 作用域(scope)6. 作用域链增强7. 变量声明7.1 var 声明变量7.2 let 声明变量7.3 const 常量声明 1. 初步了解 上下文&#xff0…

React前端面试每日一试 2.JSX是什么?JSX如何工作?

JSX是什么&#xff1f; JSX&#xff08;JavaScript XML&#xff09;是React引入的一种语法扩展&#xff0c;用于在JavaScript中编写类似HTML的结构。它让我们能够直观地描述UI的结构&#xff0c;同时保留JavaScript的编程能力。尽管JSX看起来像HTML&#xff0c;但它最终会被编…

轨迹优化 | 基于ESDF的共轭梯度优化算法(附ROS C++/Python仿真)

目录 0 专栏介绍1 数值优化&#xff1a;共轭梯度法2 基于共轭梯度法的轨迹优化2.1 障碍约束函数2.2 曲率约束函数2.3 平滑约束函数 3 算法仿真3.1 ROS C实现3.2 Python实现 0 专栏介绍 &#x1f525;课程设计、毕业设计、创新竞赛、学术研究必备&#xff01;本专栏涉及更高阶的…

Unity3D UGUI适配不同分辨率详解

前言 在Unity3D开发中&#xff0c;UGUI&#xff08;Unitys Graphical User Interface&#xff09;是构建用户界面&#xff08;UI&#xff09;的重要工具。然而&#xff0c;随着移动设备和桌面设备的分辨率日益多样化&#xff0c;确保UI能够在不同分辨率下良好显示变得尤为重要…

CAS乐观锁原理

1、什么是CAS&#xff1f; compare and swap也就是比较和交换&#xff0c;他是一条CPU的并发原语。 他在替换内存的某个位置的值时&#xff0c;首先查看内存中的值与预期值是否一致&#xff0c;如果一致&#xff0c;执行替换操作。 这个操作是一个原子性操作。 Java中基于Un…

手机免费恢复照片的软件有哪些?这2个工具来帮忙

照片是我们情感的载体&#xff0c;是记忆的碎片。它们无声地诉说着过去的故事&#xff0c;记录着生活中的点点滴滴。但意外常常是突如其来的&#xff0c;当发现手机照片丢失时&#xff0c;我们往往心痛不已。 不用担心&#xff0c;这场看似绝望的危机&#xff0c;实则有解决之…

C++ OpenCV 实现多张图片叠加 叠加文字

C OpenCV 实现多张图片叠加 叠加文字 在C中使用OpenCV叠加多张图片以及添加文字的基本步骤如下&#xff1a; 加载多张图片。 确定叠加位置。 使用cv::addWeighted叠加图片&#xff0c;可以为叠加的图片添加透明度。 使用cv::putText在图片上添加文字。 显示或保存结果图片…

Sql Server缓冲池、连接池等基本知识(附Demo)

目录 前言1. 缓存池2. 连接池3. 彩蛋 前言 基本的知识推荐阅读&#xff1a; java框架 零基础从入门到精通的学习路线 附开源项目面经等&#xff08;超全&#xff09;Mysql优化高级篇&#xff08;全&#xff09;Mysql底层原理详细剖析常见面试题&#xff08;全&#xff09; 1…

Go 环境安装配置

1、下载 wget https://go.dev/dl/go1.21.6.linux-amd64.tar.gz 2、安装 sudo tar -xvf go1.21.6.linux-amd64.tar.gz -C $HOME/3、设置环境变量及代理 # 打开 ~/.bash_profile,输入&#xff1a; export PATH$PATH:$HOME/go/bin # 设置 Go 语言代理 export GOPROXYhttps://go…

AI发展下的伦理挑战

AI发展下的伦理挑战&#xff0c;应当如何应对&#xff1f; 人工智能飞速发展的同时&#xff0c;也逐渐暴露出侵犯数据隐私、制造“信息茧房”等种种伦理风险。随着AI技术在社会各个领域的广泛应用&#xff0c;关于AI伦理和隐私保护问题日趋凸显。尽管国外已出台系列法规来规范…