使用入门
了解如何准备开发环境以使用数据绑定库,包括支持 Android Studio 中的数据绑定代码。
数据绑定库不但灵活,而且兼容性广,它是一个支持库,因此您可以在运行 Android 4.0(API 级别 14)或更高级别的设备上使用它。
建议您在项目中使用最新的 Android Plugin for Gradle。不过,1.5.0 版及更高版本支持数据绑定。有关详情,请参阅介绍如何更新 Android Plugin for Gradle的说明。
编译环境
要开始使用数据绑定,请从 Android SDK 管理器中的支持代码库下载该库。有关详情,请参阅更新 IDE 和 SDK 工具。
要将应用配置为使用数据绑定,请在应用模块的 build.gradle
文件中添加 dataBinding
元素,如以下示例所示:
android {
...
dataBinding {
enabled = true
}
}
注意:即使应用模块不直接使用数据绑定,也必须为依赖于使用数据绑定的库的应用模块配置数据绑定。
在build.gradle加入依赖
dependencies {
... implementation 'androidx.databinding:databinding-common:4.1.3'
}
单向和双向绑定
定义观察者
public class Person extends BaseObservable {
//双向绑定
private ObservableField<String> name = new ObservableField<>();
//单向绑定
private int age;
public Person(String name) {
this.name.set(name);
this.setAge(10);
}
public ObservableField<String> getName() {
return name;
}
public void setName(ObservableField<String> name) {
this.name = name;
}
@Bindable
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
notifyPropertyChanged(BR.age);
}
//事件绑定
public void onBtnClick(View view) {
new Thread(new Runnable() {
@Override
public void run() {
setAge(20);
name.set("李四");
}
});
Log.d("Person", String.format("test->name=%s", name.get()));
}
}
修改layout
<?xml version="1.0" encoding="utf-8"?>
<!--数据绑定根节点必须是layout-->
<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">
<!--声明绑定对象-->
<data>
<import type="com.example.myapplication.model.Person"></import>
<variable
name="person"
type="Person" />
</data>
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<!--包含其它layout传递person -->
<include app:person="@{person}" layout="@layout/content_main" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin"
app:srcCompat="@android:drawable/ic_dialog_email" />
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<!-- 双向绑定-->
<EditText
android:layout_width="100dp"
android:layout_height="wrap_content"
android:text="@={person.name}"></EditText>
<!-- 单向绑定-->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{Integer.toString(person.age)}"></TextView>
<!-- 绑定事件-->
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="test"
android:onClick="@{person::onBtnClick}"></Button>
</LinearLayout>
</RelativeLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>
Activity中设置数据源,ActivityMainBinding 为按照命名规则(以Activity或Fragment开头,Binding结尾)自动生成类对象
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding binding = DataBindingUtil.setContentView(this,R.layout.activity_main);
setContentView(binding.getRoot());
Person person = new Person("abc");
//设置数据源
binding.setPerson(person);
}
Fragment中设置数据源
@Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
// return inflater.inflate(R.layout.fragment_first, container, false);
FragmentFirstBinding binding = DataBindingUtil.inflate(inflater,R.layout.fragment_first,container,false);
person =new Person("张三");
binding.setPerson(person);
View mainView = binding.getRoot();
textView = mainView.findViewById(R.id.textViewTest);
return mainView;
}
自定义控件数据绑定
继续上面例子继续增加功能
attrs声明
<declare-styleable name="CustomControl">
<attr name="nLabel" format="string"></attr>
<attr name="nValue" format="string"></attr>
</declare-styleable>
layout文件
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:gravity="center">
<TextView
android:id="@+id/textViewLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="label"></TextView>
<EditText
android:id="@+id/editTextValue"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="value"
android:layout_marginLeft="10dp"></EditText>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
CustomControl实现
package com.example.myapplication.controls;
import android.content.Context;
import android.content.res.TypedArray;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.widget.EditText;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.databinding.BindingAdapter;
import androidx.databinding.InverseBindingAdapter;
import androidx.databinding.InverseBindingListener;
import com.example.myapplication.R;
public class CustomControl extends ConstraintLayout implements TextWatcher{
static String tag="CustomControl";
public interface Listener {
void onTextChanged(String password);
}
protected TextView textViewLabel;
protected EditText editTextValue;
protected String text;
protected Listener listener;
protected InverseBindingListener textInverseBindingListener;
public CustomControl(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
LayoutInflater li = (LayoutInflater) context.getSystemService(context.LAYOUT_INFLATER_SERVICE);
li.inflate(R.layout.layout_custom_control, this, true);
textViewLabel = findViewById(R.id.textViewLabel);
editTextValue = findViewById(R.id.editTextValue);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CustomControl);
String label = ta.getString(R.styleable.CustomControl_nLabel);
String value = ta.getString(R.styleable.CustomControl_nValue);
textViewLabel.setText(label);
editTextValue.setText(value);
text= value;
editTextValue.addTextChangedListener(this);
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if(s==null){
text="";
return;
}
String str = s.toString();
if(str.equals(text)){
return;
}
text = str;
editTextValue.setSelection(str.length());
if (listener != null)
listener.onTextChanged(str);
if(this.textInverseBindingListener !=null){
this.textInverseBindingListener.onChange();
}
}
@Override
public void afterTextChanged(Editable s) {
}
public void setListener(Listener listener) {
this.listener = listener;
}
public String getText() {
return text;
}
public void setText(String text){
if(this.text!=null && this.text.equals(text)){
return;
}
this.text = text;
this.editTextValue.setText(text);
this.editTextValue.setSelection(text==null?0:text.length());
}
@BindingAdapter({"vendorText"})
public static void setText(CustomControl view, String userPassword) {
view.setText(userPassword);
Log.d(tag, String.format("setText->%s",userPassword));
}
@BindingAdapter(value = {"textAttrChanged"}, requireAll = false)
public static void setTextAttrChanged(CustomControl view, InverseBindingListener inverseBindingListener) {
if (inverseBindingListener == null) {
Log.e(tag, "setTextAttrChanged->InverseBindingListener is null");
} else {
view.textInverseBindingListener = inverseBindingListener;
}
}
@InverseBindingAdapter(attribute = "vendorText", event = "textAttrChanged")
public static String getText(CustomControl view) {
return view.getText().toString();
}
}
MainActivity的layout
<com.example.myapplication.controls.CustomControl
android:layout_width="match_parent"
android:layout_height="40dp"
app:nLabel="姓名"
app:nValue="李四"
app:vendorText="@={person.name}"></com.example.myapplication.controls.CustomControl>