+2

Sử dụng view binding thay thế cho findViewById

1. Giới thiệu

View binding được giới thiệu từ Android Studio 3.6. View binding là tính năng mới cho phép bạn thay thế câu lệnh nhàm chán findViewById với việc tự động generate các class binding cho mỗi file layout XML để đơn giản code, loại bỏ việc gặp bugs, và tránh được boilerplate so với việc sử dụng findViewById.

2. Sử dụng

Lưu ý: View binding có sẵn ở phiên bản Android Studio 3.6

Để sử dụng View binding trong module, thêm viewBinding vào file build.gradle:

android {
    ...
    viewBinding {
        enabled = true
    }
}

Nếu bạn muốn bỏ qua file nào mà không cần gen view binding tự động, thêm thuộc tính sau vào mỗi file xml:

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

Một khi viewbinding được bật, class binding sẽ tự động generated cho mỗi XML layout file. Tên của class binding được generated bằng cách convert tên file layout XML thành dạng camel case và thêm hậu tố Binding phía sau cùng.

Ví dụ file xml activityawesome.xml -> ActivityAwesomeBinding

2.1. Sử dụng viewbinding trong Activity:

Để cài đặt instance của binding class sử dụng trong activity, trong method onCreate() thực hiện các bước sau:

  1. Sử dụng method inflate(), instance của class binding sẽ được tạo để sử dụng trong activity.
  2. Gọi đến tham chiếu của root view bằng getRoot()
  3. Truyền root view vào trong setContentView() để hiển thị view
private lateinit var binding: ResultProfileBinding

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

Bây giờ bạn có thể sử dụng instance của binding class để tham chiếu tới các phần tử của view rồi đó

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

2.2. Sử dụng view binding trong Fragment:

Để sử dụng instance binding class trong fragment, trong method onCreateView():

  1. Sử dụng method inflate(), instance của class binding sẽ được tạo để sử dụng trong fragment.
  2. Gọi đến tham chiếu của root view bằng getRoot()
  3. Return root view từ method onCreateView() để hiển thị view
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() {
    _binding = null
}

Bây giờ bạn có thể sử dụng các biến tham chiếu của view rồi:

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

2.3. Code được generate như thế nào:

View binding sẽ tự động generate 1 class binding cho mỗi file xml. Khi bạn chỉnh sửa file layout xml, code gen tự động sẽ được tối ưu chỉ cho class binding liên quan đến file xml đó và nó sẽ được thực hiện ở memory để đảm bảo mọi thứ nhanh nhất. Hãy cùng xem 1 file gen tự động từ file layout xml:

public final class ActivityAwesomeBinding implements ViewBinding {
  @NonNull
  private final ConstraintLayout rootView;
  @NonNull
  public final Button button;
  @NonNull
  public final TextView subtext;
  @NonNull
  public final TextView title;

View binding sẽ tự gen đúng type cho mỗi view xác định bởi id chỉ định cho view đó.

Layout include:

View binding cũng được sử dụng trong include file layout xml

<!-- activity_awesome.xml -->
<androidx.constraintlayout.widget.ConstraintLayout>
    <include android:id="@+id/includes" layout="@layout/included_buttons"
</androidx.constraintlayout.widget.ConstraintLayout>
  
<!-- included_buttons.xml -->
<androidx.constraintlayout.widget.ConstraintLayout>
    <Button android:id="@+id/include_me" />
</androidx.constraintlayout.widget.ConstraintLayout>

Lưu ý: tag <include> phải có id android:id="@+id/includes"

public final class ActivityAwesomeBinding implements ViewBinding {
  ...java
  @NonNull
  public final IncludedButtonsBinding includes;

View binding sẽ tự gen tham chiếu IncludedButtonsBinding trong ActivityAwesomeBinding

3. View binding vs findViewById

View binding có 1 vài điểm hay hơn so với findViewById:

  • Null safety: Vì view binding tạo tham chiếu trực tiếp tới view, do đó không có rủi ro như Null Pointer Exception khi invalid view ID.
  • Type safety: Fileds trong mỗi class binding có những type matching view với tham chiếu trong file xml. Do đó, không có rủi ro với class cast exception.

4. View binding vs Data Binding

View binding và Data binding cả 2 đều generate tự động class binding để bạn sử dụng tham chiếu view trực tiếp. Tuy nhiên, view binding được chú ý hơn trong các use case đơn giản và cung cấp 1 số tính năng:

  • Compile nhanh hơn: View binding không yêu cầu annotation, nên thời gian compile nhanh hơn
  • Dễ dàng sử dụng: View binding không yêu cầu tag cho file xml

Bên cạnh đó, view binding cũng có 1 số nhược điểm so với data binding:

Lưu ý: View binding chỉ thay thế cho findViewById, nếu bạn muốn tự động bind view trong file layout xml, bạn có thể sử dụng view binding cùng với data binding trong cùng module.

5. View binding vs Kotlin synthetics vs ButterKnife

Trên đây đều là 3 cách để sử dụng view trong file layout xml và được mọi người sử dụng.

ButterKnife validate nullable/not-null tại runtime, compiler không check rằng bạn đã match đúng trong layout hay chưa

Bạn nên cân nhắc sử dụng view binding nhé!

Tham khảo:

https://developer.android.com/topic/libraries/view-binding

https://medium.com/androiddevelopers/use-view-binding-to-replace-findviewbyid-c83942471fc


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí