Đối tượng dữ liệu có thể giám sát (Observable Data Objects)
Khả năng giám sát cho phép một đối tượng thông báo đến các đối tượng khác về sự thay đổi dữ liệu của nó. Khi một đối tượng có thể giám sát kết buộc với giao diện (UI) ứng dụng và một thuộc tính của đối tượng này thay đổi thì UI sẽ tự động cập nhật. Có thể định nghĩa khả năng giám sát thông qua các đối tượng (objects), các trường của đối tượng (fields) và các collections.
Giám sát thông qua các trường (Observable Fields)
Các trường của một lớp có thể được giám sát bằng cách dùng các lớp với tên bắt đầu bằng Observable theo sau là các kiểu dữ liệu cơ sở bao gồm:
- ObservableBoolean
- ObservableByte
- ObservableChar
- ObservableShort
- ObservableInt
- ObservableLong
- ObservableFloat
- ObservableDouble
- ObservableParcelable
Chúng ta cũng có thể dùng lớp generic ObservableField<Kiểu dữ liệu>. Đoạn mã sau khai báo khả năng giám sát cho các trường của lớp User:
public class User { public final ObservableField<String> fullName = new ObservableField<>(); public final ObservableInt age = new ObservableInt(0); }
Việc truy cập dữ liệu các trường của đối tượng lúc này có thể dùng phương thức set() hay get(). Đoạn mã sau sẽ khai báo hàm khởi tạo và hàm tăng tuổi (incAge) của đối tượng User:
public User(String fullName, Integer age) { this.fullName.set(fullName); this.age.set(age); } public int incAge(){ this.age.set(this.age.get()+1); return this.age.get(); }
Giám sát thông qua các collections (Observable Collections)
Một vài ứng dụng tổ chức dữ liệu thông qua các cấu trúc và chúng ta có thể dùng các collection để truy cập các cấu trúc này thông qua các khóa. Có hai lớp giám sát các collection:
- ObservableArrayMap: Hữu ích khi các khóa là kiểu tham chiếu, ví dụ String
- ObservableArrayList: Hữu ích khi khóa là một số nguyên
Đoạn mã sau dùng lớp ObservableArrayMap để khởi tạo một đối tượng lớp User:
ObservableArrayMap<String, Object> user = new ObservableArrayMap<>(); user.put("fullName", "Ngoc Minh Tran"); user.put("age", 35);
Nếu dùng lớp ObservableArrayList:
ObservableArrayList<Object> user = new ObservableArrayList<>(); user.add("Ngoc Minh Tran"); user.add(35);
Giám sát thông qua các đối tượng (Observable Objects)
Một lớp có thể được giám sát bằng cách kế thừa lớp BaseObservable. Đoạn mã sau sẽ biến lớp User thành lớp có thể giám sát:
private static class User extends BaseObservable { private String fullName; private Integer age; @Bindable public String getFullName() { return this.fullName; } @Bindable public Integer getAge() { return this.age; } public void setFullName(String fullName) { this.fullName = fullName; notifyPropertyChanged(BR.fullName); } public void setAge(Integer age) { this.age = age; notifyPropertyChanged(BR.age); } }
Data Binding phát sinh một lớp là BR trong gói chứa các ID của các tài nguyên (như TextView, EditView,…) được dùng trong Data Binding. Các chỉ thị Bindable và phương thức notifyPropertyChanged được dùng để thông báo khi có sự thay đổi xuất hiện.
Xử lý sự kiện (Event Handling)
Data Binding cho phép chúng ta viết các biểu thức xử lý sự kiện phát sinh từ các view, ví dụ phương thức onClick() xử lý sự kiện Click chuột trái của một Button.
Có hai cách xử lý sự kiện:
- Sử dụng các tham chiếu phương thức (Method References): Dùng biểu thức tham chiếu đến phương thức xử lý sự kiện dùng kí hiệu ::
- Sử dụng các kết buộc lắng nghe (Listener Bindings): Dùng biểu thức lambda khi sự kiện xảy ra
Hai cách này tương tự nhưng trong cách sử dụng tham chiếu phương thức việc thực thi lắng nghe thực sự chỉ xảy ra khi dữ liệu được kết buộc chứ không phải khi sự kiện xảy ra. Nếu ưu tiên xử lý dữ liệu khi sự kiện xảy ra thì nên dùng cách thứ hai.
Ứng dụng minh họa
Bây giờ chúng ta sẽ điều chỉnh ứng dụng MyDataBinding minh họa các khái niệm đã đề cập ở trên. Đầu tiên chúng ta sẽ thay đổi lại nội dung lớp User như sau:
public class User { public final ObservableField<String> fullName = new ObservableField<>(); public final ObservableField<Integer> age = new ObservableField<>(); public User(String fullName, Integer age) { this.fullName.set(fullName); this.age.set(age); } public int incAge(){ this.age.set(this.age.get()+1); return this.age.get(); } }
Phương thức onCreate() trong lớp MainActivity được viết lại như sau:
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = DataBindingUtil.setContentView(this,R.layout.activity_main); User user = new User("Ngoc Minh Tran",35); binding.setUser(user); }
Cuối cùng là tại phần tử Button trong tập tin activity_main.xml (chế độ Code) thay đổi giá trị thuộc tính text và onClick:
<Button android:text="Increment Age" android:onClick="@{()->user.incAge()}"/>
Chúng ta dùng biểu thức lambda để gọi hàm incAge khi sự kiện Click của Button xảy ra.
Lưu tất cả và thực thi ứng dụng. Nhấn Button để thấy sự thay đổi của trường Age. Video sau đây sẽ mô tả cách thay đổi và thực thi ứng dụng MyDataBinding
Ý kiến bài viết