Liên kết khung hiển thị   Một phần của Android Jetpack.

Liên kết khung hiển thị là một tính năng giúp bạn dễ dàng viết mã tương tác với các khung hiển thị. Sau khi bạn bật tính năng liên kết khung hiển thị trong một mô-đun, mô-đun đó sẽ tạo một lớp liên kết cho mỗi tệp bố cục XML có trong mô-đun đó. Một thực thể của lớp liên kết có chứa thông tin tham chiếu trực tiếp đến tất cả các khung hiển thị có mã nhận dạng trong bố cục tương ứng.

Trong hầu hết các trường hợp, liên kết thành phần hiển thị sẽ thay thế findViewById.

Thiết lập

Tính năng liên kết thành phần hiển thị được bật trên cơ sở từng mô-đun. Để bật tính năng liên kết thành phần hiển thị trong một mô-đun, hãy đặt tuỳ chọn bản dựng viewBinding thành true trong tệp build.gradle ở cấp mô-đun, như trong ví dụ sau:

Groovy

android {
    ...
    buildFeatures {
        viewBinding true
    }
}

Kotlin

android {
    ...
    buildFeatures {
        viewBinding = true
    }
}

Nếu bạn muốn bỏ qua một tệp bố cục trong khi tạo các lớp liên kết, hãy thêm thuộc tính tools:viewBindingIgnore="true" vào thành phần hiển thị gốc của tệp bố cục đó:

<LinearLayout
        ...
        tools:viewBindingIgnore="true" >
    ...
</LinearLayout>

Cách sử dụng

Nếu bạn bật tính năng liên kết khung hiển thị cho một mô-đun, thì một lớp liên kết sẽ được tạo cho mỗi tệp bố cục XML mà mô-đun chứa. Mỗi lớp liên kết chứa các tệp tham chiếu đến thành phần hiển thị gốc và tất cả các thành phần hiển thị có mã nhận dạng. Tên của lớp liên kết được tạo bằng cách chuyển đổi tên của tệp XML theo quy ước viết hoa Pascal case và thêm từ "Binding" vào cuối.

Ví dụ: hãy xem xét một tệp bố cục có tên là result_profile.xml chứa nội dung sau:

<LinearLayout ... >
    <TextView android:id="@+id/name" />
    <ImageView android:cropToPadding="true" />
    <Button android:id="@+id/button"
        android:background="@drawable/rounded_button" />
</LinearLayout>

Lớp liên kết được tạo có tên là ResultProfileBinding. Lớp này có hai trường: TextView có tên là nameButton có tên là button. ImageView trong bố cục không có mã nhận dạng, do đó không có tham chiếu đến mã nhận dạng đó trong lớp liên kết.

Mỗi lớp liên kết cũng bao gồm một phương thức getRoot(), cung cấp thông tin tham chiếu trực tiếp cho thành phần hiển thị gốc của tệp bố cục tương ứng. Trong ví dụ này, phương thức getRoot() trong lớp ResultProfileBinding sẽ trả về thành phần hiển thị gốc LinearLayout.

Các phần sau đây minh hoạ cách sử dụng các lớp liên kết được tạo trong các hoạt động và mảnh.

Sử dụng tính năng liên kết khung hiển thị trong các hoạt động

Để thiết lập một thực thể của lớp liên kết để sử dụng với một hoạt động, hãy thực hiện các bước sau trong phương thức onCreate() của hoạt động:

  1. Gọi phương thức inflate() tĩnh có trong lớp liên kết được tạo. Thao tác này sẽ tạo một thực thể của lớp liên kết để hoạt động sử dụng.
  2. Lấy tham chiếu đến thành phần hiển thị gốc bằng cách gọi phương thức getRoot() hoặc sử dụng cú pháp thuộc tính Kotlin.
  3. Truyền khung hiển thị gốc đến setContentView() để biến khung hiển thị đó thành khung hiển thị đang hoạt động trên màn hình.

Các bước này được thể hiện trong ví dụ sau đây:

Kotlin

private lateinit var binding: ResultProfileBinding

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = ResultProfileBinding.inflate(layoutInflater)
    val view = binding.root
    setContentView(view)
}

Java

private ResultProfileBinding binding;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    binding = ResultProfileBinding.inflate(getLayoutInflater());
    View view = binding.getRoot();
    setContentView(view);
}

Giờ đây, bạn có thể sử dụng thực thể của lớp liên kết để tham chiếu đến bất kỳ thành phần hiển thị nào:

Kotlin

binding.name.text = viewModel.name
binding.button.setOnClickListener { viewModel.userClicked() }

Java

binding.name.setText(viewModel.getName());
binding.button.setOnClickListener(new View.OnClickListener() {
    viewModel.userClicked()
});

Sử dụng tính năng liên kết khung hiển thị trong các mảnh

Để thiết lập một thực thể của lớp liên kết để sử dụng với một mảnh, hãy thực hiện các bước sau trong phương thức onCreateView() của mảnh:

  1. Gọi phương thức inflate() tĩnh có trong lớp liên kết được tạo. Thao tác này sẽ tạo một thực thể của lớp liên kết để mảnh sử dụng.
  2. Lấy tham chiếu đến thành phần hiển thị gốc bằng cách gọi phương thức getRoot() hoặc sử dụng cú pháp thuộc tính Kotlin.
  3. Trả về thành phần hiển thị gốc từ phương thức onCreateView() để biến thành phần hiển thị đó thành thành phần hiển thị đang hoạt động trên màn hình.

Kotlin

private var _binding: ResultProfileBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!

override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    _binding = ResultProfileBinding.inflate(inflater, container, false)
    val view = binding.root
    return view
}

override fun onDestroyView() {
    super.onDestroyView()
    _binding = null
}

Java

private ResultProfileBinding binding;

@Override
public View onCreateView (LayoutInflater inflater,
                          ViewGroup container,
                          Bundle savedInstanceState) {
    binding = ResultProfileBinding.inflate(inflater, container, false);
    View view = binding.getRoot();
    return view;
}

@Override
public void onDestroyView() {
    super.onDestroyView();
    binding = null;
}

Giờ đây, bạn có thể sử dụng thực thể của lớp liên kết để tham chiếu đến bất kỳ thành phần hiển thị nào:

Kotlin

binding.name.text = viewModel.name
binding.button.setOnClickListener { viewModel.userClicked() }

Java

binding.name.setText(viewModel.getName());
binding.button.setOnClickListener(new View.OnClickListener() {
    viewModel.userClicked()
});

Cung cấp gợi ý cho nhiều cấu hình

Khi bạn khai báo thành phần hiển thị trên nhiều cấu hình, đôi khi bạn nên sử dụng một loại thành phần hiển thị khác tuỳ thuộc vào bố cục cụ thể. Đoạn mã sau đây cho thấy ví dụ về việc này:

# in res/layout/example.xml

<TextView android:id="@+id/user_bio" />

# in res/layout-land/example.xml

<EditText android:id="@+id/user_bio" />

Trong trường hợp này, bạn có thể mong đợi lớp được tạo sẽ hiển thị một trường userBio thuộc loại TextView, vì TextView là lớp cơ sở chung. Do các hạn chế về kỹ thuật, trình tạo mã liên kết khung hiển thị không thể xác định điều này và tạo trường View. Điều này đòi hỏi bạn phải truyền trường sau đó bằng binding.userBio as TextView.

Để khắc phục hạn chế này, tính năng liên kết khung hiển thị hỗ trợ thuộc tính tools:viewBindingType, cho phép bạn cho trình biên dịch biết loại nào sẽ sử dụng trong mã được tạo. Trong ví dụ trước, bạn có thể sử dụng thuộc tính này để yêu cầu trình biên dịch tạo trường dưới dạng TextView:

# in res/layout/example.xml (unchanged)

<TextView android:id="@+id/user_bio" />

# in res/layout-land/example.xml

<EditText android:id="@+id/user_bio" tools:viewBindingType="TextView" />

Trong một ví dụ khác, giả sử bạn có hai bố cục, một bố cục chứa BottomNavigationView và một bố cục khác chứa NavigationRailView. Cả hai lớp này đều mở rộng NavigationBarView, chứa hầu hết thông tin chi tiết về việc triển khai. Nếu mã của bạn không cần biết chính xác lớp con nào có trong bố cục hiện tại, bạn có thể sử dụng tools:viewBindingType để đặt loại được tạo thành NavigationBarView trong cả hai bố cục:

# in res/layout/navigation_example.xml

<BottomNavigationView android:id="@+id/navigation" tools:viewBindingType="NavigationBarView" />

# in res/layout-w720/navigation_example.xml

<NavigationRailView android:id="@+id/navigation" tools:viewBindingType="NavigationBarView" />

Tính năng liên kết khung hiển thị không thể xác thực giá trị của thuộc tính này khi tạo mã. Để tránh lỗi thời gian biên dịch và thời gian chạy, giá trị này phải đáp ứng các điều kiện sau:

  • Giá trị phải là một lớp kế thừa từ android.view.View.
  • Giá trị phải là một lớp cha của thẻ được đặt trên đó. Ví dụ: các giá trị sau đây không hoạt động:

      <TextView tools:viewBindingType="ImageView" /> <!-- ImageView is not related to TextView. -->
      <TextView tools:viewBindingType="Button" /> <!-- Button is not a superclass of TextView. -->
    
  • Loại cuối cùng phải phân giải nhất quán trên tất cả các cấu hình.

Điểm khác biệt với findViewById

Liên kết khung hiển thị có những ưu điểm quan trọng so với việc sử dụng findViewById:

  • An toàn rỗng: vì tính năng liên kết khung hiển thị tạo các tệp đối chiếu trực tiếp đến khung hiển thị, nên không có nguy cơ xảy ra trường hợp ngoại lệ về con trỏ rỗng do mã khung hiển thị không hợp lệ. Ngoài ra, khi một thành phần hiển thị chỉ xuất hiện trong một số cấu hình của bố cục, trường chứa tham chiếu của thành phần hiển thị đó trong lớp liên kết sẽ được đánh dấu bằng @Nullable.
  • An toàn về loại: các trường trong mỗi lớp liên kết có các loại khớp với các thành phần hiển thị mà chúng tham chiếu trong tệp XML. Điều này có nghĩa là không có nguy cơ xảy ra ngoại lệ truyền lớp.

Những điểm khác biệt này có nghĩa là sự không tương thích giữa bố cục và mã dẫn đến bản dựng không thành công tại thời điểm biên dịch thay vì tại thời gian chạy.

So sánh với tính năng liên kết dữ liệu

Tính năng liên kết khung hiển thị và liên kết dữ liệu đều tạo ra các lớp liên kết mà bạn có thể sử dụng để tham chiếu trực tiếp các khung hiển thị. Tuy nhiên, tính năng liên kết khung hiển thị được dùng để xử lý các trường hợp sử dụng đơn giản hơn và mang lại những lợi ích sau đây so với tính năng liên kết dữ liệu:

  • Biên dịch nhanh hơn: liên kết khung hiển thị không yêu cầu xử lý chú thích, vì vậy, thời gian biên dịch sẽ nhanh hơn.
  • Dễ sử dụng: tính năng liên kết khung hiển thị không yêu cầu các tệp bố cục XML được gắn thẻ đặc biệt, vì vậy, bạn có thể áp dụng tính năng này trong ứng dụng của mình nhanh hơn. Sau khi bạn bật tính năng liên kết chế độ xem trong một mô-đun, tính năng này sẽ tự động áp dụng cho tất cả bố cục của mô-đun đó.

Mặt khác, tính năng liên kết chế độ xem có các hạn chế sau so với tính năng liên kết dữ liệu:

Do những điều cần cân nhắc này, trong một số trường hợp, tốt nhất bạn nên sử dụng cả tính năng liên kết chế độ xem và liên kết dữ liệu trong một dự án. Bạn có thể sử dụng tính năng liên kết dữ liệu trong các bố cục yêu cầu tính năng nâng cao và sử dụng tính năng liên kết chế độ xem trong các bố cục không yêu cầu tính năng nâng cao.

Tài nguyên khác

Để tìm hiểu thêm về tính năng liên kết thành phần hiển thị, hãy xem các tài nguyên bổ sung sau:

Blog

Video