Android Data Binding

Spread the love





databinding


Giới thiệu Android Data Binding

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

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

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 file xml <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(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.

 <?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

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

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にセットされる 
 
        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 <variable> 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

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 <variable>, từ View có thể sử dụng được event

activity_main.xml

<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

<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

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); //handlersにセット 
    }

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

@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

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

public class User{
    public ObservableField<String> 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 thì 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.

Tham khảo

https://qiita.com/t_sakaguchi/items/a83910a990e64f4dbdf1


Leave a Reply

Your email address will not be published. Required fields are marked *