การเชื่อมโยงมุมมอง   เป็นส่วนหนึ่งของ Android Jetpack

การเชื่อมโยงมุมมองเป็นฟีเจอร์ที่ช่วยให้คุณเขียนโค้ดที่โต้ตอบกับมุมมองได้ง่ายขึ้น เมื่อเปิดใช้การเชื่อมโยงมุมมองในโมดูล ระบบจะสร้างคลาสการเชื่อมโยงสําหรับไฟล์เลย์เอาต์ XML แต่ละไฟล์ที่อยู่ในโมดูลนั้น อินสแตนซ์ของคลาสการเชื่อมโยงมีการอ้างอิงโดยตรงไปยังมุมมองทั้งหมดที่มีรหัสในเลย์เอาต์ที่เกี่ยวข้อง

ในกรณีส่วนใหญ่ การเชื่อมโยงมุมมองจะแทนที่ findViewById

ตั้งค่า

การเชื่อมโยงมุมมองจะเปิดใช้ทีละโมดูล หากต้องการเปิดใช้การเชื่อมโยงมุมมองในข้อบังคับ ให้ตั้งค่าตัวเลือกการสร้าง viewBinding เป็น true ในไฟล์ build.gradle ระดับข้อบังคับ ดังที่แสดงในตัวอย่างต่อไปนี้

Groovy

android {     ...     buildFeatures {         viewBinding true     } }

Kotlin

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

หากต้องการให้ระบบละเว้นไฟล์เลย์เอาต์ขณะสร้างคลาสการเชื่อมโยง ให้เพิ่มแอตทริบิวต์ tools:viewBindingIgnore="true" ลงในมุมมองรูทของไฟล์เลย์เอาต์นั้น

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

การใช้งาน

หากเปิดใช้การเชื่อมโยงมุมมองสําหรับโมดูล ระบบจะสร้างคลาสการเชื่อมโยงสําหรับไฟล์เลย์เอาต์ XML แต่ละไฟล์ที่โมดูลมี คลาสการเชื่อมโยงแต่ละคลาสมีการอ้างอิงถึงมุมมองรูทและมุมมองทั้งหมดที่มีรหัส ระบบจะสร้างชื่อคลาสการเชื่อมโยงโดยแปลงชื่อไฟล์ XML เป็นรูปแบบ Pascal Case และเพิ่มคําว่า "Binding" ต่อท้าย

ตัวอย่างเช่น ลองพิจารณาไฟล์เลย์เอาต์ชื่อ result_profile.xml ที่มีข้อมูลต่อไปนี้

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

คลาสการเชื่อมโยงที่สร้างขึ้นจะเรียกว่า ResultProfileBinding คลาสนี้มี 2 ช่อง ได้แก่ TextView ชื่อ name และ Button ชื่อ button ImageView ในเลย์เอาต์ไม่มีรหัส จึงไม่มีการอ้างอิงถึงในคลาสการเชื่อมโยง

คลาสการเชื่อมโยงทุกคลาสยังมีเมธอด getRoot() ด้วย ซึ่งให้การอ้างอิงโดยตรงสำหรับมุมมองรูทของไฟล์เลย์เอาต์ที่เกี่ยวข้อง ในตัวอย่างนี้ getRoot() จะแสดงผลLinearLayout มุมมองรูทในคลาส ResultProfileBinding

ส่วนต่อไปนี้จะแสดงการใช้คลาสการเชื่อมโยงที่สร้างขึ้นในแอปพลิเคชันและฟragment

ใช้การเชื่อมโยงมุมมองในกิจกรรม

หากต้องการตั้งค่าอินสแตนซ์ของคลาสการเชื่อมโยงเพื่อใช้กับกิจกรรม ให้ทําตามขั้นตอนต่อไปนี้ในเมธอด onCreate() ของกิจกรรม

  1. เรียกใช้เมธอด inflate() แบบคงที่ซึ่งรวมอยู่ในคลาสการเชื่อมโยงที่สร้างขึ้น ซึ่งจะสร้างอินสแตนซ์ของคลาสการเชื่อมโยงเพื่อให้กิจกรรมใช้
  2. รับการอ้างอิงไปยังมุมมองรูทโดยการเรียกใช้เมธอด getRoot() หรือใช้ไวยากรณ์พร็อพเพอร์ตี้ Kotlin
  3. ส่งมุมมองรูทไปที่ setContentView() เพื่อทําให้เป็นมุมมองที่ใช้งานอยู่บนหน้าจอ

ขั้นตอนเหล่านี้แสดงอยู่ในตัวอย่างต่อไปนี้

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); }

ตอนนี้คุณใช้อินสแตนซ์ของคลาสการเชื่อมโยงเพื่ออ้างอิงมุมมองใดก็ได้ ดังนี้

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() });

ใช้การเชื่อมโยงมุมมองในส่วนย่อย

หากต้องการตั้งค่าอินสแตนซ์ของคลาสการเชื่อมโยงเพื่อใช้กับ FRG ให้ทําตามขั้นตอนต่อไปนี้ในเมธอด onCreateView() ของ FRG

  1. เรียกใช้เมธอด inflate() แบบคงที่ซึ่งรวมอยู่ในคลาสการเชื่อมโยงที่สร้างขึ้น การดำเนินการนี้จะสร้างอินสแตนซ์ของคลาสการเชื่อมโยงเพื่อให้ส่วนที่ตัดออกมาใช้
  2. รับการอ้างอิงไปยังมุมมองรูทโดยการเรียกใช้เมธอด getRoot() หรือใช้ไวยากรณ์พร็อพเพอร์ตี้ Kotlin
  3. แสดงผลมุมมองรูทจากเมธอด onCreateView() เพื่อให้เป็นมุมมองที่ใช้งานอยู่บนหน้าจอ

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; }

ตอนนี้คุณใช้อินสแตนซ์ของคลาสการเชื่อมโยงเพื่ออ้างอิงมุมมองใดก็ได้ ดังนี้

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() });
ของแฟรกเมนต์

ระบุคำแนะนำสำหรับการกำหนดค่าต่างๆ

เมื่อคุณประกาศมุมมองในการกำหนดค่าหลายรายการ ในบางครั้งก็อาจใช้มุมมองประเภทอื่นได้ ทั้งนี้ขึ้นอยู่กับเลย์เอาต์ ข้อมูลโค้ดต่อไปนี้แสดงตัวอย่าง

# in res/layout/example.xml  <TextView android:id="@+id/user_bio" />  # in res/layout-land/example.xml  <EditText android:id="@+id/user_bio" /> 

ในกรณีนี้ คุณอาจคาดหวังว่าคลาสที่สร้างขึ้นจะแสดงฟิลด์ userBio ที่มีประเภท TextView เนื่องจาก TextView เป็นคลาสฐานทั่วไป เนื่องจากข้อจํากัดทางเทคนิค ตัวสร้างโค้ดการเชื่อมโยงมุมมองจึงไม่สามารถระบุข้อมูลนี้ได้และจะสร้างช่อง View แทน ซึ่งจะต้องแคสต์ฟิลด์ในภายหลังด้วย binding.userBio as TextView

การเชื่อมโยงข้อมูลพร็อพเพอร์ตี้ของมุมมองรองรับแอตทริบิวต์ tools:viewBindingType เพื่อให้คุณบอกคอมไพเลอร์ได้ว่าจะใช้ประเภทใดในโค้ดที่สร้างขึ้น ในตัวอย่างก่อนหน้านี้ คุณสามารถใช้แอตทริบิวต์นี้เพื่อให้คอมไพเลอร์สร้างช่องเป็น 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" /> 

อีกตัวอย่างหนึ่งคือ สมมติว่าคุณมีเลย์เอาต์ 2 รายการ รายการหนึ่งมี BottomNavigationView และอีกรายการมี NavigationRailView ทั้ง 2 คลาสจะขยาย NavigationBarView ซึ่งมีรายละเอียดการใช้งานส่วนใหญ่ หากโค้ดไม่จำเป็นต้องทราบว่ามีคลาสย่อยใดอยู่ในเลย์เอาต์ปัจจุบันบ้าง คุณสามารถใช้ tools:viewBindingType เพื่อตั้งค่าประเภทที่สร้างขึ้นเป็น NavigationBarView ในทั้ง 2 เลย์เอาต์ ดังนี้

# 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" /> 

การเชื่อมโยงมุมมองไม่สามารถตรวจสอบค่าของแอตทริบิวต์นี้เมื่อสร้างโค้ด ค่าต้องเป็นไปตามเงื่อนไขต่อไปนี้เพื่อหลีกเลี่ยงข้อผิดพลาดที่เกิดขึ้นขณะคอมไพล์และข้อผิดพลาดที่เกิดขึ้นขณะรันไทม์

  • ค่าต้องเป็นคลาสที่รับค่ามาจาก android.view.View
  • ค่าต้องเป็นซุปเปอร์คลาสของแท็กที่วางไว้ เช่น ค่าต่อไปนี้ใช้ไม่ได้

      <TextView tools:viewBindingType="ImageView" /> <!-- ImageView is not related to TextView. -->   <TextView tools:viewBindingType="Button" /> <!-- Button is not a superclass of TextView. --> 
  • ประเภทสุดท้ายต้องแก้ไขให้สอดคล้องกันในการกําหนดค่าทั้งหมด

ความแตกต่างจาก findViewById

การเชื่อมโยงมุมมองมีข้อดีที่สำคัญเหนือกว่าการใช้ findViewById ดังนี้

  • ความปลอดภัยจากค่า Null: เนื่องจากการเชื่อมโยงข้อมูลวิวจะสร้างการอ้างอิงโดยตรงไปยังวิว จึงไม่มีความเสี่ยงที่จะเกิดข้อยกเว้นเกี่ยวกับ Null Pointer เนื่องจากรหัสวิวไม่ถูกต้อง นอกจากนี้ เมื่อมุมมองปรากฏในบางการกำหนดค่าของเลย์เอาต์เท่านั้น ระบบจะทําเครื่องหมายช่องที่มีข้อมูลอ้างอิงในคลาสการเชื่อมโยงด้วย @Nullable
  • ความปลอดภัยของประเภท: ฟิลด์ในคลาสการเชื่อมโยงแต่ละคลาสมีประเภทที่ตรงกับมุมมองที่อ้างอิงในไฟล์ XML ซึ่งหมายความว่าไม่มีความเสี่ยงที่จะเกิดข้อยกเว้นการแคสต์คลาส

ความแตกต่างเหล่านี้หมายความว่าเลย์เอาต์และโค้ดของคุณเข้ากันไม่ได้ ซึ่งส่งผลให้บิลด์ไม่สําเร็จเมื่อคอมไพล์ ไม่ใช่เมื่อรันไทม์

การเปรียบเทียบกับการเชื่อมโยงข้อมูล

ทั้งการเชื่อมโยงมุมมองและการเชื่อมโยงข้อมูลจะสร้างคลาสการเชื่อมโยงที่คุณสามารถใช้เพื่ออ้างอิงมุมมองโดยตรง อย่างไรก็ตาม การเชื่อมโยงข้อมูลมีไว้เพื่อจัดการกรณีการใช้งานที่ง่ายขึ้นและมีประโยชน์ต่อไปนี้เมื่อเทียบกับการเชื่อมโยงข้อมูล

  • การคอมไพล์เร็วขึ้น: การเชื่อมโยงข้อมูลพร็อพเพอร์ตี้ของวิวไม่จําเป็นต้องประมวลผลการกำกับเนื้อหา ดังนั้นเวลาในการคอมไพล์จึงเร็วขึ้น
  • ใช้งานง่าย: การเชื่อมโยงข้อมูลวิวไม่จําเป็นต้องใช้ไฟล์เลย์เอาต์ XML ที่มีแท็กพิเศษ จึงนำไปใช้ในแอปได้เร็วขึ้น เมื่อเปิดใช้การเชื่อมโยงมุมมองในโมดูลแล้ว การเชื่อมโยงจะมีผลกับเลย์เอาต์ทั้งหมดของโมดูลนั้นโดยอัตโนมัติ

ในทางกลับกัน การเชื่อมโยงข้อมูลมีข้อจํากัดต่อไปนี้เมื่อเทียบกับการเชื่อมโยงข้อมูล

ข้อควรพิจารณาเหล่านี้ทำให้ในบางกรณีคุณควรใช้ทั้งการเชื่อมโยงข้อมูลและการเชื่อมโยงข้อมูลในโปรเจ็กต์ คุณสามารถใช้การเชื่อมโยงข้อมูลในเลย์เอาต์ที่ต้องใช้ฟีเจอร์ขั้นสูง และใช้การเชื่อมโยงมุมมองในเลย์เอาต์ที่ไม่ต้องใช้

แหล่งข้อมูลเพิ่มเติม

ดูข้อมูลเพิ่มเติมเกี่ยวกับการเชื่อมโยงข้อมูลวิวได้ที่แหล่งข้อมูลต่อไปนี้

บล็อก

วิดีโอ