व्यू बाइंडिंग   Android Jetpack का हिस्सा है.

व्यू बाइंडिंग एक ऐसी सुविधा है जिसकी मदद से, व्यू के साथ इंटरैक्ट करने वाला कोड आसानी से लिखा जा सकता है. किसी मॉड्यूल में व्यू बाइंडिंग चालू करने के बाद, वह मॉड्यूल में मौजूद हर एक्सएमएल लेआउट फ़ाइल के लिए एक बाइंडिंग क्लास जनरेट करता है. बाइंडिंग क्लास के किसी इंस्टेंस में, उन सभी व्यू के रेफ़रंस शामिल होते हैं जिनके लेआउट में आईडी होता है.

ज़्यादातर मामलों में, व्यू बाइंडिंग findViewById की जगह ले लेती है.

सेटअप

व्यू बाइंडिंग, हर मॉड्यूल के हिसाब से चालू होती है. किसी मॉड्यूल में व्यू बाइंडिंग चालू करने के लिए, मॉड्यूल-लेवल build.gradle फ़ाइल में viewBinding बिल्ड विकल्प को true पर सेट करें, जैसा कि इस उदाहरण में दिखाया गया है:

Groovy

android {
    ...
    buildFeatures {
        viewBinding true
    }
}

Kotlin

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

अगर आपको बाइंडिंग क्लास जनरेट करते समय किसी लेआउट फ़ाइल को अनदेखा करना है, तो उस लेआउट फ़ाइल के रूट व्यू में tools:viewBindingIgnore="true" एट्रिब्यूट जोड़ें:

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

इस्तेमाल

अगर किसी मॉड्यूल के लिए व्यू बाइंडिंग चालू है, तो मॉड्यूल में मौजूद हर एक्सएमएल लेआउट फ़ाइल के लिए एक बाइंडिंग क्लास जनरेट की जाती है. हर बाइंडिंग क्लास में, रूट व्यू और ऐसे सभी व्यू के रेफ़रंस होते हैं जिनमें आईडी होता है. बाइंडिंग क्लास का नाम, एक्सएमएल फ़ाइल के नाम को पास्कल केस में बदलकर और आखिर में "बाइंडिंग" शब्द जोड़कर जनरेट किया जाता है.

उदाहरण के लिए, 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 कहा जाता है. इस क्लास में दो फ़ील्ड हैं: name नाम का TextView और button नाम का Button. लेआउट में मौजूद ImageView का कोई आईडी नहीं है. इसलिए, बाइंडिंग क्लास में इसका कोई रेफ़रंस नहीं है.

हर बाइंडिंग क्लास में एक getRoot() तरीका भी शामिल होता है, जो उससे जुड़ी लेआउट फ़ाइल के रूट व्यू के लिए सीधा रेफ़रंस देता है. इस उदाहरण में, ResultProfileBinding क्लास में मौजूद getRoot() तरीका, LinearLayout रूट व्यू दिखाता है.

यहां दिए गए सेक्शन में, गतिविधियों और फ़्रैगमेंट में जनरेट की गई बाइंडिंग क्लास का इस्तेमाल करने का तरीका बताया गया है.

गतिविधियों में व्यू बाइंडिंग का इस्तेमाल करना

किसी गतिविधि के साथ इस्तेमाल करने के लिए, बाइंडिंग क्लास का इंस्टेंस सेट अप करने के लिए, गतिविधि के 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()
});

फ़्रैगमेंट में व्यू बाइंडिंग का इस्तेमाल करना

फ़्रैगमेंट के साथ इस्तेमाल करने के लिए, बाइंडिंग क्लास का इंस्टेंस सेट अप करने के लिए, फ़्रैगमेंट के onCreateView() वाले तरीके में यह तरीका अपनाएं:

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

इस मामले में, आपको जनरेट की गई क्लास में TextView टाइप का फ़ील्ड userBio दिख सकता है, क्योंकि 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" />

दूसरे उदाहरण के लिए, मान लें कि आपके पास दो लेआउट हैं, जिनमें से एक में BottomNavigationView और दूसरे में NavigationRailView है. दोनों क्लास, NavigationBarView को एक्सटेंड करती हैं. इसमें लागू करने से जुड़ी ज़्यादातर जानकारी होती है. अगर आपके कोड को यह जानने की ज़रूरत नहीं है कि मौजूदा लेआउट में कौनसा सबक्लास मौजूद है, तो दोनों लेआउट में जनरेट किए गए टाइप को NavigationBarView पर सेट करने के लिए, tools:viewBindingType का इस्तेमाल किया जा सकता है:

# 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 का इस्तेमाल करने के मुकाबले, व्यू बाइंडिंग के कई फ़ायदे हैं:

  • शून्य सुरक्षा: व्यू बाइंडिंग, व्यू के लिए सीधे रेफ़रंस बनाती है. इसलिए, अमान्य व्यू आईडी की वजह से, शून्य पॉइंटर अपवाद का कोई खतरा नहीं होता. इसके अलावा, जब कोई व्यू सिर्फ़ लेआउट के कुछ कॉन्फ़िगरेशन में मौजूद होता है, तो बाइंडिंग क्लास में उसके रेफ़रंस वाले फ़ील्ड को @Nullable से मार्क किया जाता है.
  • टाइप सेफ़्टी: हर बाइंडिंग क्लास के फ़ील्ड के टाइप, उन व्यू से मेल खाते हैं जिनका रेफ़रंस एक्सएमएल फ़ाइल में दिया गया है. इसका मतलब है कि क्लास कास्ट अपवाद होने का कोई जोखिम नहीं है.

इन अंतरों का मतलब है कि आपके लेआउट और कोड के बीच काम करने में समस्या आ रही है. इस वजह से, आपका बिल्ड रनटाइम के बजाय, कंपाइल के समय पूरा नहीं हो पाता.

डेटा बाइंडिंग के साथ तुलना

व्यू बाइंडिंग और डेटा बाइंडिंग, दोनों ही बाइंडिंग क्लास जनरेट करते हैं. इनका इस्तेमाल, व्यू को सीधे तौर पर रेफ़र करने के लिए किया जा सकता है. हालांकि, व्यू बाइंडिंग का मकसद, इस्तेमाल के आसान उदाहरणों को मैनेज करना है. साथ ही, यह डेटा बाइंडिंग के मुकाबले ये फ़ायदे भी देता है:

  • ज़्यादा तेज़ी से कंपाइल होना: व्यू बाइंडिंग के लिए एनोटेशन प्रोसेस करने की ज़रूरत नहीं होती, इसलिए कंपाइल होने में कम समय लगता है.
  • इस्तेमाल में आसान: व्यू बाइंडिंग के लिए, खास तौर पर टैग की गई एक्सएमएल लेआउट फ़ाइलों की ज़रूरत नहीं होती. इसलिए, इसे ऐप्लिकेशन में तुरंत अपनाया जा सकता है. किसी मॉड्यूल में व्यू बाइंडिंग चालू करने के बाद, यह उस मॉड्यूल के सभी लेआउट पर अपने-आप लागू हो जाती है.

दूसरी ओर, डेटा बाइंडिंग की तुलना में व्यू बाइंडिंग की ये सीमाएं हैं:

इन बातों को ध्यान में रखते हुए, कुछ मामलों में प्रोजेक्ट में व्यू और डेटा, दोनों को बाइंड करना बेहतर होता है. डेटा बाइंडिंग का इस्तेमाल उन लेआउट में किया जा सकता है जिनमें बेहतर सुविधाओं की ज़रूरत होती है. साथ ही, व्यू बाइंडिंग का इस्तेमाल उन लेआउट में किया जा सकता है जिनमें बेहतर सुविधाओं की ज़रूरत नहीं होती.

अन्य संसाधन

व्यू बाइंडिंग के बारे में ज़्यादा जानने के लिए, यहां दिए गए अन्य संसाधन देखें:

ब्लॉग

वीडियो