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 provides the ability to notify other data of changes when the data object changes, binding an observable data object to the UI, and automatically updating the UI when the properties of the data object change.
Fields#
If a class has only a few properties, to give these objects the ability to observe data changes, observable fields can be used. The databinding library provides such a generic Observable class, including eight basic data types and Parcelable types, as follows:
- ObservableBoolean
- ObservableByte
- ObservableChar
- ObservableShort
- ObservableInt
- ObservableLong
- ObservableFloat
- ObservableDouble
- ObservableParcelable
Let's use it. 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 databinding, it provides an interface android.databinding.Observable. A class that implements this interface can register a listener that listens for changes to a data object and notifies 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 the properties change, 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, collections of data are often involved. The databinding library 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 the 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 observable fields, objects, and collections provided by databinding. Below is the test effect image of the above code: