Computer >> Hướng Dẫn Máy Tính >  >> Hệ Thống >> Android

Làm chủ Android Data Binding: Tích hợp dữ liệu UI liền mạch

Data binding (liên kết dữ liệu) là một kỹ thuật được sử dụng khi bạn muốn "dán" các mảnh thông tin (dữ liệu của bạn) vào các phần tử đầu vào trực quan của người dùng. Trong quá trình này, bất cứ khi nào đầu vào được cập nhật, dữ liệu phía sau nó cũng được cập nhật theo.

Đây không phải là khái niệm mới, và có rất nhiều framework đã tích hợp điều này vào thiết kế của họ (như AngularJS/React/Vue).

Chú ý của chúng ta trong bài viết này không phải là các framework front-end mà là phát triển di động. Google đã giới thiệu Data Binding Library trong Android, là một phần của Android Jetpack.

Nếu bạn chưa quen với bộ thư viện Jetpack, có thể là vì Google đã thông báo sẽ ngừng phát triển cho các thư viện support. Thay vào đó, họ sẽ chuyển sang hỗ trợ các thư viện AndroidX (là phiên bản mới hơn của các thư viện support).

Tôi biết có nhiều bài viết giải thích cách sử dụng data binding bằng adapter, nhưng bài này sẽ không tập trung vào đó. Thay vào đó, tôi sẽ chỉ ra một cách tiếp cận tối giản, cơ bản nhất cho data binding có thể giúp bạn tiết kiệm thời gian bằng cách giảm thiểu lượng code bạn phải viết.

Tại sao sử dụng Data Binding?

Nếu bạn vẫn chưa tin, hãy dành vài phút để giải thích lợi ích của việc sử dụng data binding qua một ví dụ. Giả sử bạn có một menu với ba nút tùy chỉnh, mỗi nút là một layout riêng biệt.

Làm chủ Android Data Binding: Tích hợp dữ liệu UI liền mạch
Layout của chúng ta

Một cách để tạo tất cả này là sử dụng bốn layout XML khác nhau: một cho layout chính và một cho mỗi nút trong ba nút.

Bạn cần làm như vậy vì mỗi nút sẽ dẫn người dùng đến một phần khác nhau của ứng dụng và do đó cần văn bản và hình ảnh khác nhau.

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="https://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_gravity="center_horizontal" android:layout_height="wrap_content" android:layout_width="wrap_content"> <ImageView android:id="@+id/imageView" android:layout_height="100dp" android:layout_width="100dp" android:src="@drawable/image_name" android:adjustViewBounds="true" android:scaleType="centerInside" /> <TextView android:id="@+id/textView" android:gravity="center_horizontal" android:layout_height="wrap_content" android:layout_width="match_parent" android:text="Image Text" android:textSize="16sp" /> </LinearLayout>
Layout của một nút

Được thừa nhận, đây không phải là nhiều trùng lặp code vì chúng ta chỉ xử lý ba layout. Nhưng nếu bạn nghĩ kỹ, đây là sự lãng phí thời gian xử lý toàn bộ code đó. Nếu tính đến một ứng dụng có layout phức tạp hơn, ví dụ hiển thị sản phẩm và hình ảnh của chúng, điều này có thể dẫn đến rất nhiều việc sao chép code nhàm chán.

Với data binding, chúng ta sẽ chỉ tạo một layout XML duy nhất được sử dụng bởi tất cả các nút của chúng ta.

Chúng ta bắt đầu từ đâu?

Chúng ta cần cho phép project kích hoạt data binding. Để làm vậy, chúng ta cần thêm phần tử dataBinding vào file build.gradle của ứng dụng:

android { compileSdkVersion 29 buildToolsVersion "29.0.2" defaultConfig { applicationId "com.tomerpacific.example" minSdkVersion 15 targetSdkVersion 29 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" dataBinding { //<------- enabled = true } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } }
build.gradle

Sau khi đồng bộ project, chúng ta sẽ tạo data class, sẽ được dùng để liên kết với layout.

package com.tomerpacific.example import android.graphics.drawable.Drawable data class ButtonData(val buttonText: String, val buttonImageSrc : Drawable) 
ButtonData.kt

Chú ý rằng chúng ta có hai trường trong class ButtonData:

  • buttonText — Đây là văn bản sẽ hiển thị bên dưới hình ảnh.
  • buttonImageSrc — Chịu trách nhiệm cho hình ảnh của nút.

Nếu muốn thêm dữ liệu, chúng ta chỉ cần thêm trường vào data class.

Liên kết thực tế

Tiếp theo, chúng ta cần khai báo một thuộc tính biến trong layout để có thể sử dụng. Biến này sẽ được liên kết với data class chúng ta vừa tạo. Để làm điều này, có hai việc cần làm:

  • Bọc phần tử layout gốc trong thẻ layout.
  • Thêm thẻ data chứa khai báo biến của chúng ta (buttonData).
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="https://schemas.android.com/apk/res/android"> // <---- 1 <data> <variable name="buttonData" type="com.tomerpacific.example.ButtonData"/> // <---- 2 </data> <androidx.constraintlayout.widget.ConstraintLayout xmlns:app="https://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/textView2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Example" android:textSize="30dp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:orientation="vertical" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@+id/linearLayout3" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/textView2"> <ImageButton android:layout_width="100dp" android:layout_height="100dp" android:adjustViewBounds="true" android:scaleType="centerInside" android:src="@drawable/android"> </ImageButton> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:text="Image Text" android:textSize="16sp" /> </LinearLayout> <LinearLayout android:id="@+id/linearLayout3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:orientation="vertical" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/textView2" app:layout_constraintVertical_bias="0.504"> <ImageButton android:layout_width="100dp" android:layout_height="100dp" android:adjustViewBounds="true" android:scaleType="centerInside" android:src="@drawable/android_p_logo"> </ImageButton> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:text="Image Text" android:textSize="16sp" /> </LinearLayout> <LinearLayout android:id="@+id/linearLayout2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:orientation="vertical" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.200" app:layout_constraintStart_toEndOf="@+id/linearLayout3" app:layout_constraintTop_toBottomOf="@+id/textView2" app:layout_constraintVertical_bias="0.504"> <ImageButton android:layout_width="100dp" android:layout_height="100dp" android:adjustViewBounds="true" android:scaleType="centerInside" android:src="@drawable/android_studio_icon"> </ImageButton> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:text="Image Text" android:textSize="16sp" /> </LinearLayout> </androidx.constraintlayout.widget.ConstraintLayout> </layout>
activity_main.xml

Lưu ý rằng chúng ta có thể bỏ schema từ layout chính trước đó vì nó đã được chuyển sang thẻ layout gốc. Ngoài ra, biến chúng ta thêm được liên kết trực tiếp với data class.

Trong file MainActivity, chúng ta cần thêm code để xử lý liên kết:

package com.tomerpacific.example import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import androidx.databinding.DataBindingUtil import com.tomerpacific.example.databinding.ActivityMainBinding class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val binding: ActivityMainBinding = DataBindingUtil.setContentView( this, R.layout.activity_main) binding.buttonData = ButtonData("First", resources.getDrawable(R.drawable.android)) } }
MainActivity.kt

Mỗi khi bạn tạo một biến bên trong layout, một binding class sẽ được tự động tạo cho layout đó. Trong trường hợp của chúng ta, layout tên là activity_main, nên binding class sẽ được đặt tên là ActivityMainBinding.

Quy ước luôn là tên của layout với Binding thêm vào cuối.

Vì chúng ta đã khai báo buttonData làm biến trong layout, nó được gắn vào đối tượng binding và chúng ta có thể gán cho nó một instance mới của class ButtonData.

Sau khi làm tất cả điều đó, chúng ta cuối cùng có thể sử dụng dữ liệu vừa liên kết trong layout.

<LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:orientation="vertical" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@+id/linearLayout3" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/textView2"> <ImageButton android:layout_width="100dp" android:layout_height="100dp" android:adjustViewBounds="true" android:scaleType="centerInside" android:src="@{buttonData.buttonImageSrc}"> // <---- </ImageButton> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:text="@{buttonData.buttonText}" // <---- android:textSize="16sp" />
Sử dụng biến buttonData đã liên kết

Và kết quả là:

Làm chủ Android Data Binding: Tích hợp dữ liệu UI liền mạch
Khá mượt mà, phải không?

Chờ một chút…

Chúng ta có ba nút nhưng data class chỉ dùng cho một nút, vậy làm sao để vượt qua điều này?

package com.tomerpacific.example data class ButtonsData(val buttonsData : List<ButtonData>) { fun get(index: Int) : ButtonData { return buttonsData.get(index) } }
ButtonsData.kt

Chúng ta phải ghi đè phương thức get vì nó cần được nhận diện khi sử dụng trong layout.

Sau đó, chúng ta cần thay đổi tham chiếu trong activity_main.xml:

 <data> <variable name="buttonsData" type="com.tomerpacific.example.ButtonsData"/> </data>
Chúng ta đã thay đổi tên biến và class để khớp với ButtonsData

Và chúng ta phải tạo một binding mới cho data class mới:

override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val binding: ActivityMainBinding = DataBindingUtil.setContentView( this, R.layout.activity_main) val firstButton : ButtonData = ButtonData("First", resources.getDrawable(R.drawable.android)) val secondButton : ButtonData = ButtonData("Second", resources.getDrawable(R.drawable.android_p_logo)) val thirdButton : ButtonData = ButtonData("Third", resources.getDrawable(R.drawable.android_studio_icon)) val buttonsData : ButtonsData = ButtonsData(listOf(firstButton, secondButton, thirdButton)) binding.buttonsData = buttonsData }
MainActivity.kt

Chúng ta tạo ba instance của class ButtonData. Sau đó khởi tạo đối tượng ButtonsData và gắn nó vào đối tượng binding.

Cuối cùng, chúng ta có thể sử dụng data class một cách đúng đắn trong layout:

 <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:orientation="vertical" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@+id/linearLayout3" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/textView2"> <ImageButton android:layout_width="100dp" android:layout_height="100dp" android:adjustViewBounds="true" android:scaleType="centerInside" android:src="@{buttonsData.get(0).buttonImageSrc}"> // <------- </ImageButton> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:text="@{buttonsData.get(0).buttonText}" // <-------- android:textSize="16sp" /> </LinearLayout>
Ví dụ sử dụng một phần tử
Làm chủ Android Data Binding: Tích hợp dữ liệu UI liền mạch
Hoạt động như một sự ngạc nhiên

Bài viết này được viết dựa trên kinh nghiệm phát triển ứng dụng sau:

(Bạn không bao giờ biết, nó có thể hữu ích)

Laundry Symbols - Apps on Google PlayBạn từng gặp khó khăn khi tìm hiểu ý nghĩa các ký hiệu giặt ủi? Vâng, bạn may mắn! Ứng dụng này chứa giải thích cho tất cả các ký hiệu kỳ lạ đó với giao diện dễ dùng và hình ảnhLàm chủ Android Data Binding: Tích hợp dữ liệu UI liền mạchtomerpacificApps on Google PlayLàm chủ Android Data Binding: Tích hợp dữ liệu UI liền mạch
Tải về qua Google Play Store

Bạn có thể xem toàn bộ source code tại đây:

TomerPacific/LaundrySymbolsMột ứng dụng viết bằng Kotlin hiển thị các ký hiệu giặt ủi khác nhau với giải thích :cyclone: - TomerPacific/LaundrySymbolsLàm chủ Android Data Binding: Tích hợp dữ liệu UI liền mạchTomerPacificGitHubLàm chủ Android Data Binding: Tích hợp dữ liệu UI liền mạch
Xem toàn bộ Source Code