การเชื่อมโยงมุมมอง เป็นส่วนหนึ่งของ 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()
ของกิจกรรม
- เรียกใช้เมธอด
inflate()
แบบคงที่ซึ่งรวมอยู่ในคลาสการเชื่อมโยงที่สร้างขึ้น ซึ่งจะสร้างอินสแตนซ์ของคลาสการเชื่อมโยงเพื่อให้กิจกรรมใช้ - รับการอ้างอิงไปยังมุมมองรูทโดยการเรียกใช้เมธอด
getRoot()
หรือใช้ไวยากรณ์พร็อพเพอร์ตี้ Kotlin - ส่งมุมมองรูทไปที่
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
- เรียกใช้เมธอด
inflate()
แบบคงที่ซึ่งรวมอยู่ในคลาสการเชื่อมโยงที่สร้างขึ้น การดำเนินการนี้จะสร้างอินสแตนซ์ของคลาสการเชื่อมโยงเพื่อให้ส่วนที่ตัดออกมาใช้ - รับการอ้างอิงไปยังมุมมองรูทโดยการเรียกใช้เมธอด
getRoot()
หรือใช้ไวยากรณ์พร็อพเพอร์ตี้ Kotlin - แสดงผลมุมมองรูทจากเมธอด
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 ที่มีแท็กพิเศษ จึงนำไปใช้ในแอปได้เร็วขึ้น เมื่อเปิดใช้การเชื่อมโยงมุมมองในโมดูลแล้ว การเชื่อมโยงจะมีผลกับเลย์เอาต์ทั้งหมดของโมดูลนั้นโดยอัตโนมัติ
ในทางกลับกัน การเชื่อมโยงข้อมูลมีข้อจํากัดต่อไปนี้เมื่อเทียบกับการเชื่อมโยงข้อมูล
- การเชื่อมโยงมุมมองไม่รองรับตัวแปรเลย์เอาต์หรือนิพจน์เลย์เอาต์ จึงใช้เพื่อประกาศเนื้อหา UI แบบไดนามิกจากไฟล์เลย์เอาต์ XML ได้โดยตรง
- การเชื่อมโยงข้อมูลไม่รองรับการเชื่อมโยงข้อมูลแบบ 2 ทาง
ข้อควรพิจารณาเหล่านี้ทำให้ในบางกรณีคุณควรใช้ทั้งการเชื่อมโยงข้อมูลและการเชื่อมโยงข้อมูลในโปรเจ็กต์ คุณสามารถใช้การเชื่อมโยงข้อมูลในเลย์เอาต์ที่ต้องใช้ฟีเจอร์ขั้นสูง และใช้การเชื่อมโยงมุมมองในเลย์เอาต์ที่ไม่ต้องใช้
แหล่งข้อมูลเพิ่มเติม
ดูข้อมูลเพิ่มเติมเกี่ยวกับการเชื่อมโยงข้อมูลวิวได้ที่แหล่งข้อมูลต่อไปนี้
บล็อก
วิดีโอ
แนะนำสำหรับคุณ
- หมายเหตุ: ข้อความลิงก์จะแสดงเมื่อ JavaScript ปิดอยู่
- ย้ายข้อมูลจากการสร้างโค้ด Kotlin ไปยังการเชื่อมโยงข้อมูลของวิดเจ็ต Jetpack
- เลย์เอาต์และนิพจน์การเชื่อมโยง
- สถาปัตยกรรมแอป: เลเยอร์ UI - เริ่มต้นใช้งาน - นักพัฒนาแอป Android