Giới thiệu Android Databinding
Mở đầu
Ngoài việc thay thế cho việc sử dụng findViewById
hoặc ButterKnife
datatabinding được xem như là một cách ứng dụng việc tách rời View và Logic.
Trong bài này bằng cách ứng dụng Databinding chúng ta sẽ quản lý sự thay đổi những property của object và phản ánh nó lên view
Cài đặt
trong file app/gradle thêm vào như bên dưới
1
2
3
4
5
6
7
8
|
build.gradle
android{
...
dataBinding {
enabled = true
}
}
|
Bước 1: Trước tiên, thử hiển thị giá trị của object
Định nghĩa class sẽ bind
Chuẩn bị class User giống như bên dưới
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public class User{
private String name;
public User(String name){
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
|
Layout file
Ở tag root của filexml <layout>
, định nghĩa object sẽ sử dụng bằng tag <data>
Ví dụ: định nghĩa một Object User
với name là user
(đặt tên tuỳ ý)
Từ View để access một property của bind object chúng ta sử dụng @{}
, viết như sau android:text="@{user.name}"
Nếu người dùng không định nghĩa getName()
và field name
là public thì sử dụng giá trị name
như trên.
Nhưng nếu gọi @{user.getName}
mà không định nghĩa thì build thì bị lỗi
Ngoài ra, giá trị bên trong @{}
được phép null, nghĩa là dù user
null thì NullPointerException
cũng không xãy ra.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Binding Objects -->
<data>
<variable name="user" type="com.example.databinding.User" />
</data>
<!-- Views -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.name}" />
</LinearLayout>
</layout>
|
Bind một Object
Mặc định một Binding class có tên theo dạng PascalCase
+Binding
sẽ được tự động tạo ra dựa trên tên file xml layout tương ứng.
Ví dụ:
activity_main.xml => ActivityMainBinding
fragment_sample.xml => FragmentSampleBinding
Trong Activity, Fragment chúng ta có thể lấy được instance của các class Binding và liên kết mUser
với user
trong xml như bên dưới
Trường hợp trong Activity
MainActivity.java
1
2
3
4
5
6
7
8
9
10
11
|
private User mUser = new User("Taro");
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
binding.setUser(mUser); //activity_main.xmlのuserにセットされる
binding.setHandlers(this);
}
|
Trường hợp trong Fragement
SampleFragment.java
1
2
3
4
5
6
7
8
9
|
private User mUser = new User("Taro");
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
FragmentSampleBinding binding = DataBindingUtil.inflate(inflater, R.layout.fragment_sample, container, false);
binding.setUser(mUser); //fragment_sample.xmlのuserにセットされる set
return binding.getRoot();
}
|
Với code này sau khi build màn hình sẽ hiện text “Taro”
Bước 2: Nhận event phát sinh trên view
Ở Bước 2 và Bước 3 chúng ta sẽ thử thêm chức năng tự động thay đổi tên của user bằng button
Định nghĩa event
Ở phần trên chúng ta đã chỉ định của layout, ở phần này chúng ta sẽ đăng lý EventHandlerEventHandler. Chúng ta sẽ chuẩn bị một interface làm nhiệm vụ nhận event thay đổi tên của User
SampleEventHandlers.java
1
2
3
|
public interface SampleEventHandlers {
void onChangeClick(View view);
}
|
Để liên kế với click event thì parameter của onChangeClick
phải giống với onClick()
của View.OnClickListener
Tương tự như User bằng cách khai báo trong tag , từ View có thể sử dụng được event
activity_main.xml
1
2
3
4
|
<data>
<variable name="user" type="com.example.databinding.User" />
<variable name="handlers" type="com.example.databinding.SampleEventHandlers" />
</data>
|
Liên kết event handler với click event
Để liên kết với event onclick của button chúng ta sẽ làm như sau
android:onClick="@{handlers.onChangeClick}"
activity_main.xml
1
2
3
4
5
6
|
<Button android:id="@+id/button_change"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="CHANGE"
android:onClick="@{handlers.onChangeClick}"
/>
|
android:onClick
của Button là thuộc tính tương ứng với onClick
của View.OnClickListener
và tên của thuộc tính cũng bắt nguồn từ tên method của listener.
Ví dụ trường hợp của onLongClick
của View.OnLongClickListener
thì thuộc tính tương ứng sẽ là android:onLongClick
Implement event handler
Bây giờ chúng ta sẽ implement interface trong Activity và nhận event.
MainActivity.java
1
2
3
4
5
6
7
8
9
10
11
12
|
public class MainActivity extends AppCompatActivity implements SampleEventHandlers {
private User mUser = new User("Taro");
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
binding.setUser(mUser);
binding.setHandlers(this);
}
|
Bây giờ chúng ta đã có thể đón event click của button và log sẽ được ghi.
Bước 3: Thay đổi động giá trị đang hiển thị
Tiếp theo khi button được click thử thay đổi tên User đang được hiển thị
MainActivity.java
1
2
3
4
5
6
7
8
|
@Override
public void onChangeClick(View view) {
Log.d("DEBUG", "Change User Name");
mUser.setName("Jiro");
Log.d("DEBUG", mUser.getName());
}
|
Nếu thử chạy code bên trên thì text “Jiro” sẽ hiển thị trong log nhưng trên màn hình vẫn giữ nguyên text “Taro”
Để thông báo đến View những thay đổi của các property chúng ta phải thay đổi code một chút để có thể quản lý các Object
Trường hợp dùng cách kế thừa BaseObservable
User.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
public class User extends BaseObservable{
private String name;
public User(String name){
this.name = name;
}
@Bindable
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
notifyPropertyChanged(BR.name);
}
}
|
Kế thừa lại class BaseObservable và thêm một chút thay đổi trong getter và setter
Trước tiên gắn @Bindable
trước getName()
. Với cách này một hằng số BR.name
sẽ được tạo ra.
Tiếp theo, trong setName()
thêm vào notifyPropertyChanged(BR.name)
. Lúc này từ layout, method getName()
tương ứng với BR.name sẽ được gọi.
Ở đây chúng ta đang gọi notifyPropertyChanged
trong setter nhưng thật ra có thể gọi notifyPropertyChanged
ở bất kỳ thời điểm nào bạn muốn thông báo sự thay đổi.
Trường hợp sử dụng ObservableField
Trường hợp nếu bạn không muốn dùng extends, có một cách khác là dùng ObservableField
cho các field, khi đó chú ý là kiểu của các field sẽ là ObservableField
User.java
1
2
3
4
5
6
7
|
public class User{
public ObservableField name = new ObservableField<>();
public User(String name){
this.name.set(name);
}
}
|
Với thay đổi như trên, khi tap vào button tên của user sẽ tự động thay đổi.
Tổng kết
Ưu điểm của data binding là đối với phía sử dụng binding object thì chỉ cần set object chúng ta không cần quan tâm nó được sử dụng như thế nào nữa. Đối với event cũng vậy, chúng ta không cần phải quan tâm nó phát sinh từ view như thế nào.