PS: True effort happens after action.
The previous article introduced BindAdapter
, and the series of articles on Android Jetpack components are as follows:
- Android Jetpack Component: Lifecycle
- Android Jetpack Component: LiveData
- Android Jetpack Component: ViewModel
- Android Jetpack Component: DataBinding
- Android Jetpack Component: BindingAdapter - jzman
This article will introduce how to use observable data objects. Observability refers to the ability of an object to notify other data of changes. There are mainly three types of observables:
- Fields
- Objects
- Collections
Using data binding allows data objects to notify other data of changes when data changes, binding an observable data object to the UI, so that when the properties of the data object change, the UI can be automatically updated.
Fields#
If a class has only a few properties, to enable these objects to observe data changes, observable fields can be used. Data binding provides a generic Observable class that includes eight basic data types and the Parcelable type, as follows:
- ObservableBoolean
- ObservableByte
- ObservableChar
- ObservableShort
- ObservableInt
- ObservableLong
- ObservableFloat
- ObservableDouble
- ObservableParcelable
Let's use this, here we will illustrate the use of observable fields with String and Int. First, create an entity class as follows:
/**
* Powered by jzman.
* Created on 2018/12/3 0003.
*/
public class Person {
public final ObservableField<String> name = new ObservableField<>();
public final ObservableInt age = new ObservableInt();
}
Then, declare the variables to be used in the layout file, as follows:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="person"
type="com.manu.databindsample.data.Person"/>
</data>
<LinearLayout
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{`name is `+person.name+`,age is `+person.age}"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="btnClickObservableField"
android:text="Observable Field"/>
</LinearLayout>
</layout>
Then, bind the data object in the corresponding Activity, as follows:
private Person person;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityObservableObjectSampleBinding binding =
DataBindingUtil.setContentView(this,R.layout.activity_observable_object_sample);
person = new Person();
binding.setPerson(person);
}
Finally, dynamically modify the value of person. When the property values of the Person object change, its property values will be dynamically updated, thus dynamically updating the UI, as follows:
// Dynamically modify property values
public void btnClickObservableField(View view) {
person.name.set("android");
person.age.set(10);
}
This is the use of observable fields, and the key is still the observer design pattern. See the test effect image at the end.
Objects#
When using data binding, data binding provides an interface android.databinding.Observable
. A class that implements this interface can register a listener that listens for changes to a data object, thereby notifying changes to the properties of that data object. This Observable interface has mechanisms for adding and removing listeners, but when to send data update notifications is determined by the specific implementation class. To simplify development, you can use the provided BaseObservable, which implements the listener registration mechanism. The specific class that inherits BaseObservable decides when properties change, that is, by using the @Bindable annotation on the corresponding getter methods and calling the corresponding notifyPropertyChanged method on the corresponding setter methods. Let's look at the specific usage of observable objects. First, create a data entity class as follows:
/**
* Observable data object
* Powered by jzman.
* Created on 2018/12/4 0004.
*/
public class Student extends BaseObservable{
private String name;
private int age;
@Bindable
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
notifyPropertyChanged(BR.name);
}
@Bindable
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
notifyPropertyChanged(BR.age);
}
}
Then, declare the variables to be used in the layout file, as follows:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="student"
type="com.manu.databindsample.data.Student"/>
</data>
<LinearLayout
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{`name is `+student.name+`,age is `+student.age}"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="btnClickObservableObject"
android:text="Observable Object"/>
</LinearLayout>
</layout>
Then, bind the data object in the corresponding Activity, as follows:
private Student student;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityObservableSampleBinding binding =
DataBindingUtil.setContentView(this,R.layout.activity_observable_sample);
// Observable object
student = new Student();
binding.setStudent(student);
}
Finally, dynamically modify the value of student. When the property values of the Student object change, its property values will be dynamically updated, thus dynamically updating the UI, as follows:
public void btnClickObservableObject(View view) {
student.setName("Observable Object");
student.setAge(20);
}
This is the use of observable objects. See the test effect image at the end.
Collections#
In the development process, collection data is often involved. Data binding also provides observable collection classes. Here, we will illustrate the use of ObservableMap and ObservableList with the most commonly used Map and List collections. First, declare the variables to be used in the layout file, as follows:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<!--ArrayMap-->
<import type="android.databinding.ObservableArrayMap"/>
<variable
name="arrayMap"
type="ObservableArrayMap<String,String>"/>
<!--ArrayList-->
<import type="android.databinding.ObservableList"/>
<variable
name="arrayList"
type="ObservableList<String>"/>
</data>
<LinearLayout
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{`name is `+arrayMap.name+`,age is `+arrayMap.age}"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="btnClickObservableMap"
android:text="Observable Collection: ArrayMap"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{`name is `+arrayList[0]+`,age is `+arrayList[1]}"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="btnClickObservableList"
android:text="Observable Collection: ArrayList"/>
</LinearLayout>
</layout>
Then, bind the collection data in the corresponding Activity, as follows:
private ObservableArrayMap<String,String> arrayMap;
private ObservableArrayList<String> arrayList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityObservableSampleBinding binding =
DataBindingUtil.setContentView(this,R.layout.activity_observable_sample);
// Observable collection: ArrayMap
arrayMap = new ObservableArrayMap<>();
binding.setArrayMap(arrayMap);
// Observable collection: ArrayList
arrayList = new ObservableArrayList<>();
binding.setArrayList(arrayList);
}
Finally, after binding the collection data, you can modify the collection data to observe changes in the UI, as follows:
// Observable collection: ArrayMap
public void btnClickObservableMap(View view) {
arrayMap.put("name","Observable Collection: ArrayMap");
arrayMap.put("age","30");
}
// Observable collection: ArrayList
public void btnClickObservableList(View view) {
arrayList.add("Observable Collection: ArrayList");
arrayList.add("40");
}
This is the use of observable collections.
Test Effect#
Through the above small examples, I believe you can easily use the fields, objects, and collections with observability provided by data binding. Below is the test effect image of the above code: