遵义门户网站/怎么根据视频链接找到网址
DataBinding
- 前言
- 使用前需要了解
- 一、基础用法
- 二、引入布局(include、viewStub)
- 三、单向绑定 (Data变化通知View)
- 1、BaseObservable
- 2、ObservableField
- 四、双向绑定 (Data变化通知View,View变化反馈给数据)
- 五、配合LiveData的写法
- 1、事例延续上面代码修改,做双向绑定
- 2、引入布局场景
- 六、BindingAdapter
- 七、BindingConversion
- 八、支持的运算符和关键字
- 参考地址
前言
Jetpack 是一个丰富的组件库,它的组件库按类别分为 4 类,分别是架构(Architecture)、界面(UI)、 行为(behavior)和基础(foundation)。
每个组件都可以单独使用,也可以配合在一起使-用。每个组件都给用户提供了一个标准, 能够帮助开发者遵循最佳做法,减少样板代码并编写可在各种 Android 版本和设备中一致运行的代码,让开发者能够集中精力编写重要的业务代码。
DataBinding 是 Google 在 Jetpack 中推出的一款数据绑定的支持库,利用该库可以实现在页面组件中直接绑定应用程序的数据源。使其维护起来更加方便,架构更明确简介。
使用前需要了解
运行环境:
Android Studio Chipmunk | 2021.2.1 Patch 1
Build #AI-212.5712.43.2112.8609683, built on May 19, 2022
Runtime version: 11.0.12+7-b1504.28-7817840 amd64
- 应用DataBinding,在App的build.gradle:
android {buildFeatures {
// viewBinding = truedataBinding = true}
- 想在哪个页面使用DataBinding,就修改对应的布局文件
添加 layout 标签
<?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"><!--我的布局文件--><androidx.constraintlayout.widget.ConstraintLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity">// .... 布局内容</androidx.constraintlayout.widget.ConstraintLayout></layout>
- 编译后就会有对应布局的binding了
ActivityMainBinding mBinding;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_main);// mBinding = ActivityMainBinding.inflate(getLayoutInflater());
// setContentView(mBinding.getRoot());mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
注意:DataBinding实现了ViewBinding ,所以ViewBinding的用法也适用。
一、基础用法
当前事例实现:
- 向XML中设置指定的Data格式数据,提供给View引用
- 向XML设置点击事件
- 向XML设置方法所在类,调用静态方法
- 引用string资源文件
XML
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"><data><!--提供方法的类--><import type="com.yoshin.kt.demo_databinding.StringUtils" /><!--点击事件--><import type="com.yoshin.kt.demo_databinding.MainActivity.Listener" /><!--实体类--><variablename="student"type="com.yoshin.kt.demo_databinding.bean.Student" /><!--实体类--><variablename="student2"type="com.yoshin.kt.demo_databinding.bean.Student" /><!--点击事件--><variablename="lintener"type="Listener" /></data><!--我的布局文件--><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".MainActivity"><TextViewandroid:layout_width="match_parent"android:layout_height="50dp"android:gravity="center"android:text="你好 世界!" /><TextViewandroid:layout_width="match_parent"android:layout_height="50dp"android:gravity="center"android:onClick="@{()->lintener.onClick(student)}"android:text="@{@string/student_name + student.name,default = 小明}"android:textColor="@color/teal_200" /><TextViewandroid:layout_width="match_parent"android:layout_height="50dp"android:gravity="center"android:text="@{StringUtils.getAge(student.year)}"android:textColor="@color/teal_200" /><EditTextandroid:layout_width="match_parent"android:layout_height="50dp"android:afterTextChanged="@{lintener.afterStudentNameChanged}"android:gravity="center"android:text="@{@string/student_2 + @string/student_name + student2.name,default = 小明}"android:textColor="@color/teal_200" /></LinearLayout></layout>
Activity
@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);ActivityMainBinding mBinding = ActivityMainBinding.inflate(getLayoutInflater());setContentView(mBinding.getRoot());Student student = new Student();student.setName("小黑");student.setYear("18");Student student2 = new Student();student2.setName("小绿");mBinding.setStudent(student);mBinding.setStudent2(student2);mBinding.setLintener(new Listener());}public class Listener {public void onClick(Student student) {Toast.makeText(MainActivity.this, student.getName(), Toast.LENGTH_SHORT).show();}public void afterStudentNameChanged(Editable editable) {Toast.makeText(MainActivity.this, editable.toString(), Toast.LENGTH_SHORT).show();}}
此时的写法,数据没有绑定
二、引入布局(include、viewStub)
以 include 为例(DataBinding不支持merge标签):
view_include_patriarch.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"><data><variablename="patriarch"type="com.yoshin.kt.demo_databinding.bean.Patriarch" /></data><androidx.constraintlayout.widget.ConstraintLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"><TextViewandroid:layout_width="match_parent"android:layout_height="50dp"android:gravity="center"android:text="@{@string/str_name + patriarch.name,default = 小明的爸爸}"android:textColor="@color/teal_200" /></androidx.constraintlayout.widget.ConstraintLayout></layout>
main.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:binding="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"><data><!--提供方法的类--><import type="com.yoshin.kt.demo_databinding.StringUtils" /><!--点击事件--><import type="com.yoshin.kt.demo_databinding.MainActivity.Listener" /><!--实体类--><variablename="student"type="com.yoshin.kt.demo_databinding.bean.Student" /><!--实体类--><variablename="student2"type="com.yoshin.kt.demo_databinding.bean.Student" /><!--点击事件--><variablename="lintener"type="Listener" /></data><!--我的布局文件--><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".MainActivity">... 略<includeandroid:id="@+id/ic_patriarch"layout="@layout/view_include_patriarch"binding:patriarch="@{student.patriarch}" /></LinearLayout></layout>
需要在main.xml里添加:
xmlns:binding="http://schemas.android.com/apk/res-auto"
但是鼓捣了半天都引用不到属性
不过没有关系!!!硬写吧,是好用的~ 这应该是个BUG吧
参考:dataBinding中使用include :https://blog.csdn.net/chuyouyinghe/article/details/124354463
三、单向绑定 (Data变化通知View)
如下事例延续上面的操作续写
1、BaseObservable
public class Student extends BaseObservable {@Bindableprivate String name;@Bindableprivate String year;public String getName() {return name;}public void setName(String name) {this.name = name;}public String getYear() {return year;}public void setYear(String year) {this.year = year;notifyPropertyChanged(BR.year);}}
如上,如果通过 setYear(String year)
方法设置 year
时,如果数据有变化就会通知View进行更新,通过重写 TextView.setText()
方法确认了这一点,如果数据无变换不会通知到View更新;
setName(String name)
调用不会通知View更新,因为没有调用到 notifyPropertyChanged(id)
。
-
@Bindable
需要使用到更新的Key,需要添加此注解 -
notifyPropertyChanged(int fieldId)
如果个Key,数据改变,就更新View -
notifyChange()
刷新所有Key
2、ObservableField
参考 :Android 安卓DataBinding(四)·单向绑定 ObservableField:https://blog.csdn.net/qq_40881680/article/details/101847386
续写测试ObservableField
参考上面做的,我这里也不好使啊,记一下!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!不好使!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
public class Student extends BaseObservable {private final ObservableField<String> name = new ObservableField<>();private final ObservableField<String> year = new ObservableField<>();private final ObservableField<Patriarch> patriarch = new ObservableField<>();public String getName() {return name.get();}public void setName(String name) {this.name.set(name);}public String getYear() {return year.get();}public void setYear(String year) {this.year.set(year);}public Patriarch getPatriarch() {return patriarch.get();}public void setPatriarch(Patriarch patriarch) {this.patriarch.set(patriarch);}}
在调用如下代码时,XML没有跟着实时刷新啊,(⊙o⊙)…不理解源码的痛
student.setYear(String.valueOf(System.currentTimeMillis()));
public class Patriarch {/*** 继承 BaseObservableField 父类继承 BaseObservable 实现 Observable*/private ObservableField<String> name;private ObservableInt intId;private ObservableLong longId;private ObservableDouble doubleId;private ObservableBoolean isOk;private ObservableByte oByte;private ObservableFloat floatId;private ObservableChar charId;private ObservableShort shortId;public Patriarch() {name = new ObservableField<>();}/*** 继承 ObservableField*/private ObservableParcelable<Friend> friend;public String getName() {return name.get();}public void setName(String name) {this.name.set(name);}/*** 继承 List*/ObservableList<String> list;ObservableArrayList<String> arrayList;/*** 继承 Map*/ObservableMap<String, String> map;ObservableArrayMap<String, String> arrayMap;}
先这样吧 。没好使。
四、双向绑定 (Data变化通知View,View变化反馈给数据)
<TextViewandroid:id="@+id/tv_2"android:layout_width="match_parent"android:layout_height="50dp"android:gravity="center"android:onClick="@{()->lintener.onClick(student)}"android:text="@={student.name,default = 小明}"android:textColor="@color/teal_200" />
如上,即双向绑定的写法
@={student.name,default = 小明}
区别于正常写法,需要多写个=
号
注意是,如果写了“=”就不能直接引用string文件了,也不能引用静态方法。
测试的时候,配合的是 标题三、单向绑定,中的 1.BaseObservable进行的测试,验证双向绑定OK
五、配合LiveData的写法
1、事例延续上面代码修改,做双向绑定
- ViewModel
public class MainViewModel extends AndroidViewModel {public MainViewModel(@NonNull Application application) {super(application);}final MutableLiveData<Student> mutableLiveData = new MutableLiveData<>();public MutableLiveData<Student> getMutableLiveData() {return mutableLiveData;}public void setMutableLiveData(Student student) {mutableLiveData.setValue(student);}final MutableLiveData<String> stringMutableLiveData = new MutableLiveData<>();public MutableLiveData<String> getStringMutableLiveData() {return stringMutableLiveData;}public void setStringMutableLiveData(String str) {stringMutableLiveData.setValue(str);}
- XML
<data>.... 略<variablename="viewModel"type="com.yoshin.kt.demo_databinding.MainViewModel" /><!--我的布局文件--><androidx.core.widget.NestedScrollViewandroid:layout_width="match_parent"android:layout_height="match_parent"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".MainActivity">... 略<EditTextandroid:id="@+id/tv_1"android:layout_width="match_parent"android:layout_height="50dp"android:gravity="center"android:onClick="@{()->lintener.onClick(student)}"android:text="@={viewModel.mutableLiveData.name}"android:textColor="@color/teal_200" /><com.yoshin.kt.demo_databinding.MyTextViewandroid:id="@+id/tv_2"android:layout_width="match_parent"android:layout_height="50dp"android:gravity="center"android:text="@={viewModel.stringMutableLiveData}"android:textColor="@color/teal_200" />
- 调用
public class MainActivity extends AppCompatActivity {private static final String TAG = "MainActivity";ActivityMainBinding mBinding;private MainViewModel mVM= ViewModelProvider.AndroidViewModelFactory.getInstance(this.getApplication()).create(MainViewModel.class);@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);... 略mBinding.setLifecycleOwner(this);mBinding.setViewModel(mVM);mVM.getMutableLiveData().observe(this, new Observer<Student>() {@Overridepublic void onChanged(Student student) {Log.i(TAG, " getMutableLiveData observe == " + new Gson().toJson(student));}});mVM.setMutableLiveData(student);mVM.getStringMutableLiveData().observe(this, new Observer<String>() {@Overridepublic void onChanged(String s) {Log.i(TAG, " getStringMutableLiveData observe == " + new Gson().toJson(s));}});mVM.setStringMutableLiveData("这就是个String");
如此,可以实现双向绑定。
虽然实现了双向绑定,但是还有需要说的地方:
LiveData <T
的泛型 T
是JavaBean
还是String
类型,影响观察者模式的回调
- 当
T
是Student (JavaBean)
调用 mVM.setMutableLiveData(student);
,日志 getMutableLiveData observe == xxx
只会输出一次,无论值本身地址变化,还是内部数据变化;
调用 mBinding.tv1.setText(“xxxx”);
,日志 getMutableLiveData observe == xxx
不会输出,但是值本身是变化的(通过点击按钮打印,mutableLiveData 内部值是变化的)。
- 当
T
是String
进入页面第一次调用 mVM.setStringMutableLiveData(str);
,日志 getStringMutableLiveData observe == xxx
会输出一次;
之后,调用 mVM.setStringMutableLiveData(str);
,如果值是有变化的,日志 getStringMutableLiveData observe == xxx
会输出两次,重写了TextView,发现setText()的方法,夹在中间;
如下:
14:10:29.827 14131-14131/com.yoshin.kt.demo_databinding I/MainActivity: getStringMutableLiveData observe == "setString 修改后String的值"14:10:29.829 14131-14131/com.yoshin.kt.demo_databinding I/Main-MyTextView: setText14:10:29.832 14131-14131/com.yoshin.kt.demo_databinding I/MainActivity: getStringMutableLiveData observe == "setString 修改后String的值"
如果值没有变化,日志 getStringMutableLiveData observe == xxx
会输出一次;
调用 mBinding.tv2.setText(“xxxx”);
,日志 getStringMutableLiveData observe == xxx
会输出一次。
综上所述,推荐使用当 T
是 (JavaBean)
的方式,容易控制。
2、引入布局场景
二、引入布局(include、viewStub)的写法在这就失效了,这里就要修改了,如下即可:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"><data><variablename="viewModel"type="com.yoshin.kt.demo_databinding.MainViewModel" /><variablename="patriarch"type="com.yoshin.kt.demo_databinding.bean.Patriarch" /></data><androidx.constraintlayout.widget.ConstraintLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"><TextViewandroid:layout_width="match_parent"android:layout_height="50dp"android:gravity="center"android:text="@{@string/str_name + viewModel.mutableLiveData.patriarch.name,default = 小明的爸爸}"android:textColor="@color/teal_200" /></androidx.constraintlayout.widget.ConstraintLayout></layout>
改成 传入 viewModel,就可以在数据改变的时候View更新。
六、BindingAdapter
用途: 支持自定义属性,或者是修改原有属性
- 自定义属性
一个参数的
public class ImageBindingAdapter {@BindingAdapter("imageUrl")public static void setImageUrl(ImageView view, String url) {Log.i(TAG, "setImageUrl: ");Glide.with(view).load(url).into(view);}
<ImageViewimageUrl="@{viewModel.mutableLiveData.url}"android:layout_width="100dp"android:layout_height="100dp"/>
多个参数的
@BindingAdapter(value = {"imageUrl", "placeholder", "error"},requireAll = false)
public static void loadImage(ImageView view, String url, Drawable placeholder, Drawable error) {RequestOptions options = new RequestOptions();options.placeholder(placeholder);options.error(error);Glide.with(view).load(url).apply(options).into(view);
}
<ImageViewandroid:layout_width="100dp"android:layout_height="100dp"android:layout_marginTop="10dp"app:imageUrl="@{`https://goss.veer.com/creative/vcg/veer/800water/veer-136599950.jpg`}"app:placeholder="@{@drawable/icon}"/>
- 修改属性
public class TextViewAdapter {@BindingAdapter("android:text")public static void setText(TextView view, CharSequence text) {//省略特殊处理...String txt = text.toString().toLowerCase();view.setText(txt);}
}
<!--使用dataBinding的TextView--><TextViewandroid:id="@+id/tvData"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="10dp"android:background="#a37c7c"android:text="@{`这是TextView...`}"android:textSize="16sp" />
这么写完,databinding都会调用这个方法,不推荐
转 Android Jetpack组件之BindingAdapter详解:https://blog.csdn.net/jzman/article/details/106699816
七、BindingConversion
Android Jetpack组件之BindingAdapter详解:https://blog.csdn.net/jzman/article/details/106699816
Android DataBinding 从入门到进阶,看这一篇就够:https://blog.csdn.net/Eqiqi/article/details/121670801
八、支持的运算符和关键字
绑定表达式支持的运算符和关键字
算术运算符 + - / * %
字符串连接运算符 +
逻辑运算符 && ||
二元运算符 & | ^
一元运算符 + - ! ~
移位运算符 >> >>> <<
比较运算符 == > < >= <=(请注意,< 需要转义为 <)
instanceof
分组运算符 ()
字面量运算符 - 字符、字符串、数字、null
类型转换
方法调用
字段访问
数组访问 []
三元运算符 ?:
Null 合并运算符 ??
属性引用.
集合操作[],可用于数组,列表,映射;
字面常量
资源@,但是有些资源类型需要显式指明;
Android-DataBinding-使用-高阶:https://www.jianshu.com/p/b5762e72f56f
参考地址
Android DataBinding 从入门到进阶,看这一篇就够:https://blog.csdn.net/Eqiqi/article/details/121670801
https://wenku.baidu.com/view/0a12a6356f175f0e7cd184254b35eefdc8d31592.html
https://developer.android.google.cn/jetpack/androidx/releases/databinding
转自 Android Jetpack架构全家桶,学完可从零搭建一个Android项目架构:http://px.sxjnk.cn/enjoy/advertorial/article_6