Android Data Binding: Observability(Giữ UI Luôn hiển thị dữ liệu mới nhất)
Bài đăng này đã không được cập nhật trong 8 năm
Android Data Binding rất dễ sử dụng để chèn dữ liệu vào UI
(Giao diện người dùng). Tuy nhiên, khi dữ liệu được cập nhật mới thì không có một thông báo gì đến UI
để UI
có thể cập nhật lại. Thực sự thì nó không được tốt lắm khi server
gửi một thông báo cập nhật và bạn muốn người dùng sẽ nhìn thấy sự thay đổi đó trên UI. Android Data Binding cung cấp một vài cách giúp bạn có thể đồng bộ dữ liệu với UI
. Cho nên ta có thuật ngữ Observability và hôm nay tôi giới thiệu đến các bạn Interface Observable.
1.Model
Tôi khởi tạo một POJO có tên là Foo
, với một thuộc tính là bar
. Sau đó tôi sẽ bind
vào UI
của tôi.
public class Foo {
private int bar;
public int getBar() {
return bar;
}
public void setBar(int bar) {
this.bar = bar;
}
}
Cái tôi mong muốn ở đây là UI
của tôi sẽ thay đổi mỗi khi tôi gọi method setBar
. Vì vậy hãy xem nào thế nào để Data Binding theo kịp với sự thay đổi của dữ liệu nhé.
2.Observable
Đối tượng của bạn implement lại interface Observable
, và override lại 2 methods:
void addOnPropertyChangedCallback(OnPropertyChangedCallback c);
void removeOnPropertyChangedCallback(OnPropertyChangedCallback c);
Đối tượng OnPropertyChangedCallback sẽ tạo ra các callback để thông báo mỗi khi các field
trong object của bạn có sự thay đổi.
public abstract void onPropertyChanged(Observable sender,
int propertyId);
Class
của bạn phải nên sử dụng annotate @Bindable
với mỗi getter
.
@Bindable
public int getBar() {
return bar;
}
Đoạn code ở trên nói rằng DataBinding Framework có thuộc tính là observable
và cũng tự động generate ra một định danh trong class BR
trong ứng dụng của bạn. Class BR
này giống với class R
, Nhưng nó ràng buộc các nguồn tài nguyên mà bạn sẽ sử dụng cho propertyId.
Android data binding cung cấp cho bạn class PropertyChangeRegistry
để làm dễ dàng hơn cho việc track listener
:
public class Foo implements Observable {
private PropertyChangeRegistry registry =
new PropertyChangeRegistry();
private int bar;
@Binder
public int getBar() {
return bar;
}
public void setBar(int bar) {
this.bar = bar;
registry.notifyChange(this, BR.bar);
}
@Override
public void addOnPropertyChangedCallback(
OnPropertyChangedCallback callback) {
registry.add(callback);
}
@Override
public void removeOnPropertyChangedCallback(
OnPropertyChangedCallback callback) {
registry.remove(callback);
}
}
3. BaseObservable
Nếu Model
của bạn kế thừa đối tượng BaseObservable
. Vì việc làm Observability
sẽ dễ dàng hơn bằng cách thực thi các function nằm trong Observable interface
. Bạn chỉ cần phải annotate
thuộc tính và notify sự thay đổi
public class Foo extends BaseObservable {
private int bar;
@Bindable
public int getBar() {
return bar;
}
public void setBar(int bar) {
this.bar = bar;
notifyPropertyChanged(BR.bar);
}
}
4.ObservableField
Observable
và BaseObservable
sử dụng đơn giản nhưng cũng có chút gì đó phức tạp. Vì vậy tôi giới thiệu thêm ObservableField
và các kiểu dữ liệu nguyên thủy. Để sử dụng ObservableField
, chỉ có thể khai báo public final
fields đó trong class của bạn. Tôi sẽ có 2 thuộc tính tại thời điểm này một là dữ liệu kiểu nguyên thủy và kiểu reference
:
public class Foo {
public final ObservableInt bar = new ObservableInt();
public final ObservableField<String> baz =
new ObservableField<>();
Bạn có thể sử dụng nó giống như các thuộc tính bình thường khi dùng biểu thức binding
:
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{foo.baz}"/>
Trong khi các biểu thức binding
vẫn còn được sử dụng, Java
yêu cầu gọi setters và getters:
foo.bar.set(age);
String name = foo.baz.get();
5.ObservableMap
Có khi bạn sử dụng dữ liệu không thể xác định được. Bạn vẫn có thể tạo ra các prototype
và các data format
từ server trả về và bạn không muốn tạo ra các đối tượng cho họ thì đã có ObservableMap
và ObservableArrayMap
giúp bạn tạo ra các cấu trúc dữ liệu mà bạn có thể lờ mờ mường tượng ra.
Với ObservableMap
, bạn có thể truy cập các giá trị trong Map<>
của bạn giống như bất kỳ HashMap
, LinkedHashMap
hay Map
và UI
sẽ được cập nhật khi có thay đổi xảy ra. Ví dụ :
<data>
<variable name="product"
type="android.databinding.ObservableMap<String, Object>"/>
</data>
<!-- ... -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text='@{product["name"]}'/>
Và bạn sử dụng ObservableMap
trên code của bạn như sau :
ObservableMap<String, Object> product = new ObservableArrayMap<>();
binding.setProduct(product);
product.put("name", "Golf Ball");
Và bất cứ lúc nào đối tượng product
thay đổi, nó sẽ cập nhật lại UI.
6. Kết luận
Nhiều UI không cần thiết phải nhận được thông tin khi có thay đổi dữ liệu, vì vậy bạn không cần phải thêm observability
vào trong toàn bộ các model của bạn .Mặt khác nó có thể sẽ rất tốt để giao diện của bạn sẽ tự động cập nhật khi server của bạn gửi dữ liệu mới xuống hoặc người dùng làm thay đổi một phần của UI và các phần UI còn lại sẽ cập nhật theo phần thay đổi đó.
Xong rồi. giờ hãy chọn một trong các observability
ở phía trên mà bạn cảm thấy phù hợp. Hầu hết theo tôi thấy thì BaseObservable
hoặc ObservableFields
được sử dụng nhiều. Nhưng các observability
cũng đều có các công dụng riêng của chúng.
All rights reserved