Tìm hiểu về Data Binding trong Android – Phần 2
Một thư viện rất đáng giá mà Android M sở hữu: thư viện Data Binding. Thư viện giúp các lập trình viên không phải viết quá nhiều code để “ghép dữ liệu” vào các component trên file layout XML nữa. Nếu bạn nào đã từng lập trình web thì có thể nôm na hiểu thư viện này giống với ...
-
Một thư viện rất đáng giá mà Android M sở hữu: thư viện Data Binding. Thư viện giúp các lập trình viên không phải viết quá nhiều code để “ghép dữ liệu” vào các component trên file layout XML nữa.
-
Nếu bạn nào đã từng lập trình web thì có thể nôm na hiểu thư viện này giống với AngularJS. Chúng ta có các “layout template” với “data holder”, giờ chỉ cần định nghĩa nguồn dữ liệu, tự chúng sẽ hiển thị theo data tương ứng (mô hình MVVM).
-
Nếu trước kia để bind dữ liệu vào component, chúng ta sẽ phải làm 2 bước:
//bind component vào 1 biến txtHello = (TextView) findViewById(R.id.txtHello); //bind data vào biến để rồi component sẽ thay đổi data hiển thị tương ứng. txtHello.setText(“Hello, how are you?”);
- Còn bây giờ? Hãy xem một ví dụ đơn giản để hiểu thư viện này hoạt động thế nào?
- Cài đặt Android M SDK (v23) và Android Studio 1.3
Để sử dụng được thư viện Data Binding, bạn cần phải thỏa mãn 3 điều kiện sau:
- Android Support Library > 15.0 (cần để download thư viện này trên maven/jcenter, hoặc nếu không muốn sử dụng Maven thì download package Android Support Library > 23 (toàn bộ thư viện offline)
- Android M SDK 23.0 và build tool của nó.
- Android Studio 1.3 (hiện Google chỉ còn support Android Studio nên bạn nào dùng Eclipse chắc sẽ phải đợi các nhóm làm Tool support)
** Source code demo được dựa trên help chính thức của google: https://developer.android.com/tools/data-binding/guide.html.
Trong phần 2 này mình sẽ chỉ cho các bạn cách dùng databinding 1 cách chi tiết và sức mạnh của nó. Đầu tiên mình sẽ hướng dẫn các bạn viết 1 ứng dụng đồng hồ đếm thời gian. Giao diện ứng dụng trông như thế này:
Ta bắt đầu nhé:
Tại file build.gradle trong thẻ android bạn thêm dòng sau.
dataBinding { enabled = true }
- Ta tạo MyModel.java trông nó như thế này:
public class MyModel extends BaseObservable { @Bindable public String time; // Thời gian để hiển thị lên màn hình @Bindable public boolean stop; //biến này sẽ là cờ cho biết là đồng hồ có chay //hay không? public MyModel(String time, boolean stop) { this.time = time; this.stop = stop; } public boolean isStop(){ return stop; } }
Ở file res/values/string.xml
<string name="txt_start">Start</string> <string name="txt_stop">Stop</string> //Bạn tạo ra 1 class MyHandler.java như sau: public class MyHandlers { public void onClickReset(View view) { } public void onClickStart(View view){ } }
- Ở đây mình cho class MyHandler.java vào trong MainActivity cho dễ điều khiển. Tiếp đến trong file xml ta sẽ làm làm như thế này (Ví dụ của mình là file activity_main):
<?xml version="1.0" encoding="utf-8"?> <layout> <data> <variable name="handlers" type="com.android.demodatabinding .MainActivity.MyHandlers"/> <variable name="mymodel" type="com.android.demodatabinding. model.MyModel"/> </data> <LinearLayout xmlns:android="http://schemas.android.com /apk/res/android" android:layout_awidth="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:layout_awidth="match_parent" android:textSize="38sp" android:textStyle="bold" android:layout_gravity="center" android:text="@{mymodel.time}" android:gravity="center" android:layout_margin="10dp" android:layout_height="wrap_content" /> <Button android:layout_gravity="center" android:layout_awidth="wrap_content" android:layout_height="wrap_content" android:layout_margin="10dp" android:textColor="#FFFFFF" android:text="@{mymodel.stop ? @string /txt_stop : @string/txt_start}" android:onClick="@{handlers.onClickStart}" android:background="@drawable/bg_button"/> <Button android:layout_gravity="center" android:layout_awidth="wrap_content" android:layout_height="wrap_content" android:layout_margin="10dp" android:text="Reset" android:textColor="#FFFFFF" android:onClick="@{handlers.onClickReset}" android:background="@drawable/bg_button"/> </LinearLayout> </layout>
**Mình sẽ giải thích cho bạn nhé:
**Đầu tiên ở dòng này
<data> <variable name="handlers" type="com.android.demodatabinding .MainActivity.MyHandlers"/> <variable name="mymodel" type="com.android.demodatabinding .model.MyModel"/> </data>
- Ta khai báo hai biến là handlers với class tương ứng là MyHandlers và biến mymodel tương ứng với class MyModel.
android:text="@{mymodel.time}"
Có nghĩa là bạn hiển thị cái đồng hồ đếm thời gian lên cái TextView.
android:text="@{mymodel.stop ? @string/txt_stop : @string/txt_start}"
- Có nghĩ là nếu cái biến stop là true thì button sẽ hiển thì là Stop trái lại thì là Start.
android:onClick="@{handlers.onClickStart}"
-
Nghĩa là khi click button này nó sẽ gọi hàm onClickStart ra.
-
Bây giờ ta quay lại MyModel để tạo ra 1 phương thức setTime và isStop để có thể update được dữ liệu ngay trên View. Và ta hoàn chình code của MyModel thế này:
public class MyModel extends BaseObservable { @Bindable public String time; // Thời gian để hiển thị lên màn hình @Bindable public boolean stop; //biến này sẽ là cờ cho biết là đồng hồ có chay hay không? public MyModel(String time, boolean stop) { this.time = time; this.stop = stop; } public boolean isStop(){ return stop; } public void setStop(boolean stop) { this.stop = stop; notifyPropertyChanged(BR.stop); } public void setTime(String time) { this.time = time; notifyPropertyChanged(BR.time); } }
Bạn để ý có thấy trong hàm set có.
notifyPropertyChanged(BR.stop);
Cái này nó sẽ giúp cho bạn update dữ liệu lên view khi model thay đổi.
Trong activity (của mình là MainActivity nhé). Mình cần có một biến để đếm thời gian. 1 cái vòng lặp để đếm. Và 1 hàm xử lý đếm đó. Vậy ta có hàm xử lý đồng hồ
private void setRunnable(){ runnable = new Runnable() { @Override public void run() { String format = "%02d:%02d:%02d"; String time = String.format(format, TimeUnit.MILLISECONDS.toHours(count*1000), TimeUnit.MILLISECONDS .toMinutes(count*1000) - TimeUnit.HOURS. toMinutes(TimeUnit.MILLISECONDS .toHours(count*1000)), TimeUnit.MILLISECONDS .toSeconds(count*1000) - TimeUnit.MINUTES .toSeconds(TimeUnit .MILLISECONDS.toMinutes(count*1000))); model.setTime(time); count++; h.postDelayed(this, 1000); } }; }
Ta sẽ dùng Handler để đếm nó
private void runCount(){ h.postDelayed(runnable, 1000); }
Sau 1s là mình sẽ chạy cái runable mà trong cái runable mình lại gọi tiếp cái handler này. Như vậy thì ta sẽ có cái đồng hồ rồi.
Bây giờ muốn dừng thì sao. Tại hàm onClickStart trong class MyHandler ta sẽ cho như thế này
public void onClickStart(View view){ if(!model.isStop()){ model.setStop(true); runCount(); }else { model.setStop(false); h.removeCallbacks(runnable); } }
Cuối cùng ta viết hàm MainActivity nó như thế này:
public class MainActivity extends AppCompatActivity { MyModel model; MyHandlers myHandlers = new MyHandlers(); Runnable runnable; Handler h; long count =0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main); model = new MyModel("00:00:00", false); binding.setMymodel(model); binding.setHandlers(myHandlers); setRunnable(); h = new Handler(); //runCount(); } private void runCount(){ h.postDelayed(runnable, 1000); } /*cai dat runable*/ private void setRunnable(){ runnable = new Runnable() { @Override public void run() { String format = "%02d:%02d:%02d"; String time = String.format(format, TimeUnit.MILLISECONDS .toHours(count*1000), TimeUnit.MILLISECONDS .toMinutes(count*1000) - TimeUnit.HOURS .toMinutes(TimeUnit .MILLISECONDS.toHours(count*1000)), TimeUnit .MILLISECONDS .toSeconds(count*1000) - TimeUnit.MINUTES .toSeconds(TimeUnit. MILLISECONDS.toMinutes(count*1000))); model.setTime(time); count++; h.postDelayed(this, 1000); } }; } public class MyHandlers { public void onClickReset(View view) { count = 0; } public void onClickStart(View view){ if(!model.isStop()){ model.setStop(true); runCount(); }else { model.setStop(false); h.removeCallbacks(runnable); } } } }
Bạn hãy xậy dựng theo ví dụ để xem kết quả khi mình sử dụng databinding.
Ngoài ra chúng ta sẽ không thấy các câu lệnh findViewById và setXXX nữa. Chỉ cần nguồn dữ liệu, tự động data_binding sẽ bind dữ liệu đó cho các component. Ngoài support kiểu POJO đơn giản, Data Binding support hàng loạt case khác nhau như:
-
Binding event
-
Sử dụng import để tweak Layout Detail
-
Sử dụng nhiều nguồn variables
-
Viết custom binding
-
Hỗ trợ expression language
-
Hỗ trợ observables objects (các object khi có thay đổi prop, view sẽ tự thay đổi tương ứng)
-
View và ViewStubs
-
Dynamic Binding
-
Converters
-
và ...
-
Mình xin kết thúc phần 2 ở đây.
** Các tài liệu tham khảo** .
0.http://www.developer.com/ws/android/programming/how-to-use-android-data-binding.html 1.https://halfthought.wordpress.com/2016/03/23/2-way-data-binding-on-android/ 2.http://qiita.com/izumin5210/items/2784576d86ce6b9b51e6 3.https://realm.io/news/data-binding-android-boyar-mount/