DataBinding在Android中的使用
一、概述
DataBinding可以实现数据单向或者双向的绑定,让开发比较方便。通过数据变化更新UI,完全由数据驱动。
二、使用
1、集成DataDinding
添加 dataBinding.enabled true 和 dataBinding { enabled = true }
示例如下:
apply plugin: 'com.android.application'
android {
compileSdkVersion 30
buildToolsVersion "30.0.1"
defaultConfig {
applicationId "com.stormdzh.myapplication"
minSdkVersion 15
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
dataBinding.enabled true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
//添加这行就算引入了
dataBinding {
enabled = true
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
implementation 'com.facebook.fresco:fresco:2.3.0'
}
2、实现xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="title"
type="java.lang.String" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:textColor="#000000"
android:id="@+id/tvTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{title}"/>
</LinearLayout>
</layout>
3、Activity中添加测试代码
public class TestDataBindingActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityTestDatabindingBinding viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_test_databinding);
//setContentView(R.layout.activity_test_databinding);
viewDataBinding.setLifecycleOwner(this);
viewDataBinding.setTitle("测试字符串");
}
}
4、集成中问题
1.Activity需要集成AppCompatActivity
2.写完DataBindingUtil.setContentView(this, R.layout.activity_test_databinding)后,可以输入ActivityTestDatab...让编译器不全这个变量。这个变量是Android生成的,自己手写可能会有误差。
三、常用知识
1、引入对象
需要把类引入进来,之后给他设置一个name。
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="title"
type="java.lang.String" />
<variable
name="user"
type="com.stormdzh.myapplication.User" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:textColor="#000000"
android:id="@+id/tvTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{title}"/>
<TextView
android:textColor="#000000"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.name}"/>
</LinearLayout>
</layout>
2、引入静态方法
需要把工具类引入进来,之后通过@{AppUtil.int2Str(user.age)}调用
public class AppUtil {
public static String int2Str(int num){
return String.valueOf(num);
}
}
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<import type="com.stormdzh.myapplication.AppUtil" />
<variable
name="title"
type="java.lang.String" />
<variable
name="user"
type="com.stormdzh.myapplication.User" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:textColor="#000000"
android:id="@+id/tvTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{title}"/>
<TextView
android:textColor="#000000"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.name}"/>
<TextView
android:textColor="#000000"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{AppUtil.int2Str(user.age)}"/>
</LinearLayout>
</layout>
3、DataBinding中引入数据的另一种形式
<data>
<import type="java.lang.String"/>
<import type="com.stormdzh.myapplication.User"
alias="User"/>
<variable name="title" type="String" />
<variable name="user" type="User" />
</data>
4、如何使用data中引入和定义的内容
1.variable——使用variable中的bean对象,如果是属性,直接使用@{name.field}
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.name}" />
2.如果使用的无参数方法,@{() -> name.function()}
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="@{() -> listener.onClickListenerBinding()}"
android:text="@{Utility.autoAppend(v,user.name)}" />
3.点击事件需要把点击的view传入并操作,@{(v) -> name.function(v)} 括号中间的v就表示当前的这个view的参数名称(可以自定义),直接作为参数名使用就可以。
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="@{(v) -> listener.onClickListenerBinding(v)}"
android:text="@{user.name}" />
5、DataBinding是使用点击事件
//java代码
public class TestDataBindingActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityTestDatabindingBinding viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_test_databinding);
// setContentView(R.layout.activity_test_databinding);
viewDataBinding.setLifecycleOwner(this);
viewDataBinding.setTitle("测试字符串");
User user = new User();
user.name="张三";
user.age=18;
viewDataBinding.setUser(user);
user.name="李四";
//设置点击事件
viewDataBinding.setEventHandler(new OnEventHandler());
}
public class OnEventHandler{
public void onClick(View v){
Toast.makeText(TestDataBindingActivity.this,"响应了点击事件",Toast.LENGTH_SHORT).show();
}
}
}
//布局文件
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<import type="com.stormdzh.myapplication.AppUtil" />
<variable
name="title"
type="java.lang.String" />
<variable
name="user"
type="com.stormdzh.myapplication.User" />
<variable
name="eventHandler"
type="com.stormdzh.myapplication.TestDataBindingActivity.OnEventHandler" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:onClick="@{(v)->eventHandler.onClick(v)}"
android:layout_width="match_parent"
android:layout_height="45dp"
android:background="#543298"
android:gravity="center"
android:text="更新数据"
android:textColor="#000000" />
<TextView
android:id="@+id/tvTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{title}"
android:textColor="#000000" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.name}"
android:textColor="#000000" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{AppUtil.int2Str(user.age)}"
android:textColor="#000000" />
</LinearLayout>
</layout>
6、include使用
系统会自动生成一个自定义属性bind,通过bind可以直接对include中的layout中绑定的数据直接进行赋值,这样就可以间接的控制include中的操作。
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bind="http://schemas.android.com/apk/res-auto">
<data>
<variable name="user" type="com.example.User"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/name"
bind:user="@{user}"/>
<include layout="@layout/contact"
bind:user="@{user}"/>
</LinearLayout>
</layout>
7、ViewStub使用
首先ViewStub在尚未添加到xml中时,获取Bindgin对象肯定是无效的,所以需要在OnInflateListener中回调被添加的事件,然后再去获Bing对象。
binding = DataBindingUtil.setContentView(this, R.layout.activity_view_stub);
binding.viewStub.setOnInflateListener(new ViewStub.OnInflateListener() {
@Override
public void onInflate(ViewStub stub, View inflated) {
ViewStubBinding binding = DataBindingUtil.bind(inflated);
User user = new User("name", "刘备");
binding.setUser(user);
}
});
四、绑定可观察数据;绑定可观察数据由三种方式:object,field,collections。
1、继承BaseObservable,当数据发生变化的时候调用:notifyChange方法
public class User extends BaseObservable {
public String name;
public int age;
}
//模拟数据变化
public class OnEventHandler{
public void onClick(View v){
Toast.makeText(TestDataBindingActivity.this,"响应了点击事件",Toast.LENGTH_SHORT).show();
user.name="阿波罗";
user.notifyChange();
}
}
2、一个对象中只有一个或者几个变量需要观察变化,比如age需要变化
public class User {
public String name;
//把int改为ObservableInt
public ObservableInt age;
}
对于基本类型和Parcelable我们可以直接使用对应的包装类:
ObservableBoolean
ObservableByte
ObservableChar
ObservableShort
ObservableInt
ObservableLong
ObservableFloat
ObservableDouble
ObservableParcelable
之后再Activity通过修改ObservableInt的值,在调用notifyChange更新
public class TestDataBindingActivity extends AppCompatActivity {
private User user;
ObservableInt observableAge = new ObservableInt(18);
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityTestDatabindingBinding viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_test_databinding);
// setContentView(R.layout.activity_test_databinding);
viewDataBinding.setLifecycleOwner(this);
viewDataBinding.setTitle("测试字符串");
user = new User();
user.name = "张三";
user.age = observableAge;
viewDataBinding.setUser(user);
//设置点击事件
viewDataBinding.setEventHandler(new OnEventHandler());
}
public class OnEventHandler {
public void onClick(View v) {
Toast.makeText(TestDataBindingActivity.this, "响应了点击事件", Toast.LENGTH_SHORT).show();
user.name = "阿波罗";
observableAge.set(90);
observableAge.notifyChange();
}
}
}
四、LiveData+DataBinbing
实体类:
public class Person {
public String name;
public int age;
}
Xml文件
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="liveData"
type="androidx.lifecycle.MutableLiveData<com.stormdzh.myapplication.Person>" />
<variable
name="eventHandler"
type="com.stormdzh.myapplication.LiveDataEntityBindingActivity.OnEventHandler" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:onClick="@{(v)->eventHandler.onClick(v)}"
android:layout_width="match_parent"
android:layout_height="45dp"
android:background="#543298"
android:gravity="center"
android:text="更新数据"
android:textColor="#000000" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{liveData.name}"
android:textColor="#000000" />
</LinearLayout>
</layout>
java类的实现
public class LiveDataEntityBindingActivity extends AppCompatActivity {
MutableLiveData<Person> mutableLiveData;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityEntityLiveDatabindingBinding viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_entity_live_databinding);
viewDataBinding.setLifecycleOwner(this);
mutableLiveData =new MutableLiveData<>();
//设置点击事件
viewDataBinding.setEventHandler(new OnEventHandler());
viewDataBinding.setLiveData(mutableLiveData);
Person p =new Person();
p.name= "首次";
mutableLiveData.setValue(p);
}
public class OnEventHandler {
public void onClick(View v) {
Toast.makeText(LiveDataEntityBindingActivity.this, "响应了点击事件", Toast.LENGTH_SHORT).show();
Person p =new Person();
p.name= "更新";
mutableLiveData.setValue(p);
}
}
}
五、双向绑定
上述的单向绑定是数据变化后更新UI,而双向绑定是指其中任意一个变化后都会同步更新到另一个。双向绑定使用@={}表达式来实现:
<data>
...
<variable name="input" type="androidx.databinding.ObservableField<String"/>
</data>
...
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@={input}"/>
目前已经支持双向绑定的列表:
image.png
六、DataBinding加载图片
Xml文件实现逻辑
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<import type="com.stormdzh.myapplication.AppUtil" />
<variable
name="imageUrl"
type="java.lang.String" />
<variable
name="eventHandler"
type="com.stormdzh.myapplication.PicDataBindingActivity.OnEventHandler" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:layout_width="match_parent"
android:layout_height="45dp"
android:background="#543298"
android:gravity="center"
android:onClick="@{(v)->eventHandler.onClick(v)}"
android:text="更新数据"
android:textColor="#000000" />
<com.facebook.drawee.view.SimpleDraweeView
imageUrl="@{imageUrl}"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="10dp" />
</LinearLayout>
</layout>
java代码实现
public class PicDataBindingActivity extends AppCompatActivity {
ActivityPicDatabindingBinding viewDataBinding;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_pic_databinding);
// setContentView(R.layout.activity_test_databinding);
viewDataBinding.setLifecycleOwner(this);
//设置点击事件
viewDataBinding.setEventHandler(new OnEventHandler());
String path = "https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1089874897,1268118658&fm=26&gp=0.jpg";
viewDataBinding.setImageUrl(path);
}
public class OnEventHandler {
public void onClick(View v) {
Toast.makeText(PicDataBindingActivity.this, "响应了点击事件", Toast.LENGTH_SHORT).show();
String path = "https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=1056193884,1712488622&fm=26&gp=0.jpg";
viewDataBinding.setImageUrl(path);
}
}
@BindingAdapter("imageUrl")
public static void loadImage(SimpleDraweeView iv, String imageUrl) {
Log.i("dzh", "加载图片了");
loadPic(iv, imageUrl);
}
private static void loadPic(SimpleDraweeView mSimpleDraweeView, String path) {
Uri uri = Uri.parse(path);
mSimpleDraweeView.setImageURI(uri);
}
}
五、总结
DataBing还有很多知识点需要完善,但是大致的要点都介绍了。现在也都晚上9点多了,有点写不动了,以后再花点时间好好整理其中的细节,大家一起共勉!之后奉上Demo源码!