बाइंडिंग अडैप्टर

सही फ़्रेमवर्क कॉल करने के लिए, बाइंडिंग अडैप्टर ज़िम्मेदार होते हैं मान सेट करता है. एक उदाहरण है प्रॉपर्टी मान सेट करना, जैसे setText() तरीका. अन्य उदाहरण के लिए, एक इवेंट लिसनर सेट करना, जैसे setOnClickListener() तरीका.

डेटा बाइंडिंग लाइब्रेरी से, वैल्यू सेट करने का तरीका तय किया जा सकता है. अपना बाइंडिंग लॉजिक दें और लौटाए गए ऑब्जेक्ट का टाइप तय करें अडैप्टर का उपयोग करके देखा जा सकता है.

एट्रिब्यूट की वैल्यू सेट करना

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

तरीका अपने-आप चुनने की सुविधा

example नाम के एट्रिब्यूट के लिए, लाइब्रेरी अपने-आप तरीका ढूंढ लेती है setExample(arg), जो आर्ग्युमेंट के तौर पर काम करने वाले टाइप को स्वीकार करता है. नेमस्पेस विशेषता को नहीं माना जाता. सिर्फ़ एट्रिब्यूट के नाम और टाइप का इस्तेमाल किया गया है आपको इस बारे में ज़्यादा जानकारी चाहिए.

उदाहरण के लिए, android:text="@{user.name}" एक्सप्रेशन दिया गया, लाइब्रेरी ऐसी setText(arg) तरीका ढूंढता है जो इसके दिए गए टाइप को स्वीकार करती हो user.getName(). अगर user.getName() का रिटर्न टाइप String है, तो लाइब्रेरी, setText() तरीके की कोशिश करती है, जो String आर्ग्युमेंट को स्वीकार करे. अगर एक्सप्रेशन एक int दिखाता है. लाइब्रेरी में एक setText() तरीका खोजा जाता है int तर्क स्वीकार करता है. एक्सप्रेशन का टाइप सही होना चाहिए. आप अगर ज़रूरी हो, तो रिटर्न वैल्यू को कास्ट करें.

डेटा बाइंडिंग तब भी काम करती है, जब दिए गए नाम के साथ कोई एट्रिब्यूट मौजूद न हो. आप डेटा बाइंडिंग का इस्तेमाल करके किसी भी सेटर के लिए एट्रिब्यूट बनाता है. उदाहरण के लिए, सहायता क्लास DrawerLayout इसके एट्रिब्यूट नहीं हैं, लेकिन इसमें कई सेटर हैं. नीचे दिया गया लेआउट अपने-आप setScrimColor(int) और addDrawerListener(DrawerListener) app:scrimColor और app:drawerListener के लिए सेटर के रूप में विधियां एट्रिब्यूट:

<androidx.drawerlayout.widget.DrawerLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:scrimColor="@{@color/scrim}"
    app:drawerListener="@{fragment.drawerListener}">

एक कस्टम तरीका नाम तय करें

कुछ एट्रिब्यूट में ऐसे सेटर होते हैं जो नाम से मेल नहीं खाते. इन स्थितियों में, एट्रिब्यूट को सेटर के साथ जोड़ा जा सकता है. इसके लिए, BindingMethods एनोटेशन. एनोटेशन का इस्तेमाल क्लास के साथ किया जाता है और इसमें एक से ज़्यादा हो सकते हैं BindingMethod एनोटेशन, बदले गए नाम वाले हर तरीके के लिए एक एनोटेशन. बाइंडिंग मेथड ऐसे एनोटेशन होते हैं जिनमें को अपने ऐप्लिकेशन की किसी भी क्लास में जोड़ा जा सकता है.

यहां दिए गए उदाहरण में, android:tint एट्रिब्यूट setImageTintList(ColorStateList) तरीका—setTint() तरीके के साथ नहीं:

Kotlin

@BindingMethods(value = [
    BindingMethod(
        type = android.widget.ImageView::class,
        attribute = "android:tint",
        method = "setImageTintList")])

Java

@BindingMethods({
       @BindingMethod(type = "android.widget.ImageView",
                      attribute = "android:tint",
                      method = "setImageTintList"),
})

आम तौर पर, आपको Android फ़्रेमवर्क क्लास में सेटर का नाम बदलने की ज़रूरत नहीं होती है. कॉन्टेंट बनाने एट्रिब्यूट अपने-आप लागू होने के लिए, नाम कन्वेंशन का इस्तेमाल करके पहले से ही लागू किए जाते हैं ढूंढने के तरीके ढूंढने हैं.

पसंद के मुताबिक लॉजिक दें

कुछ एट्रिब्यूट के लिए, कस्टम बाइंडिंग लॉजिक की ज़रूरत होती है. उदाहरण के लिए, android:paddingLeft एट्रिब्यूट के लिए सेटर. इसके बजाय, setPadding(left, top, right, bottom) तरीका दिया जाता है. स्टैटिक बाइंडिंग अडैप्टर BindingAdapter एनोटेशन की मदद से, यह तय किया जा सकता है कि किसी एट्रिब्यूट के सेटर को कैसे कॉल किया जाए.

Android फ़्रेमवर्क क्लास के एट्रिब्यूट में पहले से ही BindingAdapter मौजूद है एनोटेशन. नीचे दिए गए उदाहरण में paddingLeft एट्रिब्यूट:

Kotlin

@BindingAdapter("android:paddingLeft")
fun setPaddingLeft(view: View, padding: Int) {
    view.setPadding(padding,
                view.getPaddingTop(),
                view.getPaddingRight(),
                view.getPaddingBottom())
}

Java

@BindingAdapter("android:paddingLeft")
public static void setPaddingLeft(View view, int padding) {
  view.setPadding(padding,
                  view.getPaddingTop(),
                  view.getPaddingRight(),
                  view.getPaddingBottom());
}

पैरामीटर के टाइप अहम होते हैं. पहला पैरामीटर, एट्रिब्यूट से जुड़ा व्यू. दूसरा पैरामीटर तय करता है कि दिए गए एट्रिब्यूट के लिए बाइंडिंग एक्सप्रेशन में स्वीकार किया गया टाइप.

बाइंडिंग अडैप्टर अन्य तरह के कस्टमाइज़ेशन के लिए भी उपयोगी हैं. उदाहरण के लिए, इमेज लोड करने के लिए, कस्टम लोडर को वर्कर थ्रेड से कॉल किया जा सकता है.

आपके पास ऐसे अडैप्टर भी हो सकते हैं जिन्हें कई एट्रिब्यूट मिलते हैं, जैसा कि यहां दिखाया गया है नीचे दिया गया उदाहरण:

Kotlin

@BindingAdapter("imageUrl", "error")
fun loadImage(view: ImageView, url: String, error: Drawable) {
    Picasso.get().load(url).error(error).into(view)
}

Java

@BindingAdapter({"imageUrl", "error"})
public static void loadImage(ImageView view, String url, Drawable error) {
  Picasso.get().load(url).error(error).into(view);
}

यहां दिए गए उदाहरण के मुताबिक, अपने लेआउट में अडैप्टर का इस्तेमाल किया जा सकता है. नोट जोड़ें जिसे @drawable/venueError, आपके ऐप्लिकेशन में मौजूद किसी संसाधन के बारे में बताता है. चारों तरफ़ @{} के साथ संसाधन इसे एक मान्य बाइंडिंग एक्सप्रेशन बनाता है.

<ImageView app:imageUrl="@{venue.imageUrl}" app:error="@{@drawable/venueError}" />

अडैप्टर को तब कॉल किया जाता है, जब imageUrl और error का इस्तेमाल किसी ImageView ऑब्जेक्ट है. imageUrl एक स्ट्रिंग है और error एक Drawable. अगर आपको इनमें से कोई भी विशेषता सेट होने पर अडैप्टर को कॉल किया जाना है, तो वैकल्पिक requireAll अडैप्टर को false के लिए फ़्लैग करता है, जैसा कि इस उदाहरण में दिखाया गया है:

Kotlin

@BindingAdapter(value = ["imageUrl", "placeholder"], requireAll = false)
fun setImageUrl(imageView: ImageView, url: String?, placeHolder: Drawable?) {
    if (url == null) {
        imageView.setImageDrawable(placeholder);
    } else {
        MyImageLoader.loadInto(imageView, url, placeholder);
    }
}

Java

@BindingAdapter(value={"imageUrl", "placeholder"}, requireAll=false)
public static void setImageUrl(ImageView imageView, String url, Drawable placeHolder) {
  if (url == null) {
    imageView.setImageDrawable(placeholder);
  } else {
    MyImageLoader.loadInto(imageView, url, placeholder);
  }
}

बाइंडिंग अडैप्टर मेथड, अपने हैंडलर में पुरानी वैल्यू इस्तेमाल कर सकते हैं. तरीका पुरानी और नई वैल्यू लेने से पहले, एट्रिब्यूट के लिए सभी पुरानी वैल्यू के बारे में बताना चाहिए, और इसके बाद नई वैल्यू डालें, जैसा कि इस उदाहरण में दिखाया गया है:

Kotlin

@BindingAdapter("android:paddingLeft")
fun setPaddingLeft(view: View, oldPadding: Int, newPadding: Int) {
    if (oldPadding != newPadding) {
        view.setPadding(newPadding,
                    view.getPaddingTop(),
                    view.getPaddingRight(),
                    view.getPaddingBottom())
    }
}

Java

@BindingAdapter("android:paddingLeft")
public static void setPaddingLeft(View view, int oldPadding, int newPadding) {
  if (oldPadding != newPadding) {
      view.setPadding(newPadding,
                      view.getPaddingTop(),
                      view.getPaddingRight(),
                      view.getPaddingBottom());
   }
}

इवेंट हैंडलर का इस्तेमाल सिर्फ़ इंटरफ़ेस या ऐब्स्ट्रैक्ट क्लास के साथ किया जा सकता है एब्सट्रैक्ट तरीके का इस्तेमाल करें, जैसा कि नीचे दिए गए उदाहरण में दिखाया गया है:

Kotlin

@BindingAdapter("android:onLayoutChange")
fun setOnLayoutChangeListener(
        view: View,
        oldValue: View.OnLayoutChangeListener?,
        newValue: View.OnLayoutChangeListener?
) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
        if (oldValue != null) {
            view.removeOnLayoutChangeListener(oldValue)
        }
        if (newValue != null) {
            view.addOnLayoutChangeListener(newValue)
        }
    }
}

Java

@BindingAdapter("android:onLayoutChange")
public static void setOnLayoutChangeListener(View view, View.OnLayoutChangeListener oldValue,
       View.OnLayoutChangeListener newValue) {
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
    if (oldValue != null) {
      view.removeOnLayoutChangeListener(oldValue);
    }
    if (newValue != null) {
      view.addOnLayoutChangeListener(newValue);
    }
  }
}

अपने लेआउट में इस इवेंट हैंडलर का इस्तेमाल इस तरह करें:

<View android:onLayoutChange="@{() -> handler.layoutChanged()}"/>

अगर किसी लिसनर के पास कई तरीके हैं, तो उसे एक से ज़्यादा लिसनर में बांटना चाहिए. उदाहरण के लिए, View.OnAttachStateChangeListener इसके दो तरीके हैं: onViewAttachedToWindow(View) और onViewDetachedFromWindow(View). एट्रिब्यूट और हैंडलर में अंतर करने के लिए, लाइब्रेरी दो इंटरफ़ेस उपलब्ध कराती है इन कीवर्ड का इस्तेमाल करें:

Kotlin

// Translation from provided interfaces in Java:
@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
interface OnViewDetachedFromWindow {
    fun onViewDetachedFromWindow(v: View)
}

@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
interface OnViewAttachedToWindow {
    fun onViewAttachedToWindow(v: View)
}

Java

@TargetApi(VERSION_CODES.HONEYCOMB_MR1)
public interface OnViewDetachedFromWindow {
  void onViewDetachedFromWindow(View v);
}

@TargetApi(VERSION_CODES.HONEYCOMB_MR1)
public interface OnViewAttachedToWindow {
  void onViewAttachedToWindow(View v);
}

एक लिसनर बदलने से दूसरे लिसनर पर असर पड़ सकता है, इसलिए आपको ऐसे अडैप्टर की ज़रूरत होगी जो दोनों में से किसी एक एट्रिब्यूट या फिर दोनों के लिए काम करता है. requireAll को false पर सेट किया जा सकता है यह बताने के लिए व्याख्या कि हर विशेषता को बाइंडिंग असाइन नहीं किया जाना चाहिए एक्सप्रेशन, जैसा कि नीचे दिए गए उदाहरण में दिखाया गया है:

Kotlin

@BindingAdapter(
        "android:onViewDetachedFromWindow",
        "android:onViewAttachedToWindow",
        requireAll = false
)
fun setListener(view: View, detach: OnViewDetachedFromWindow?, attach: OnViewAttachedToWindow?) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {
        val newListener: View.OnAttachStateChangeListener?
        newListener = if (detach == null && attach == null) {
            null
        } else {
            object : View.OnAttachStateChangeListener {
                override fun onViewAttachedToWindow(v: View) {
                    attach.onViewAttachedToWindow(v)
                }

                override fun onViewDetachedFromWindow(v: View) {
                    detach.onViewDetachedFromWindow(v)
                }
            }
        }

        val oldListener: View.OnAttachStateChangeListener? =
                ListenerUtil.trackListener(view, newListener, R.id.onAttachStateChangeListener)
        if (oldListener != null) {
            view.removeOnAttachStateChangeListener(oldListener)
        }
        if (newListener != null) {
            view.addOnAttachStateChangeListener(newListener)
        }
    }
}

Java

@BindingAdapter({"android:onViewDetachedFromWindow", "android:onViewAttachedToWindow"}, requireAll=false)
public static void setListener(View view, OnViewDetachedFromWindow detach, OnViewAttachedToWindow attach) {
    if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB_MR1) {
        OnAttachStateChangeListener newListener;
        if (detach == null && attach == null) {
            newListener = null;
        } else {
            newListener = new OnAttachStateChangeListener() {
                @Override
                public void onViewAttachedToWindow(View v) {
                    if (attach != null) {
                        attach.onViewAttachedToWindow(v);
                    }
                }
                @Override
                public void onViewDetachedFromWindow(View v) {
                    if (detach != null) {
                        detach.onViewDetachedFromWindow(v);
                    }
                }
            };
        }

        OnAttachStateChangeListener oldListener = ListenerUtil.trackListener(view, newListener,
                R.id.onAttachStateChangeListener);
        if (oldListener != null) {
            view.removeOnAttachStateChangeListener(oldListener);
        }
        if (newListener != null) {
            view.addOnAttachStateChangeListener(newListener);
        }
    }
}

ऊपर दिया गया उदाहरण थोड़ा जटिल है, क्योंकि View क्लास addOnAttachStateChangeListener() और removeOnAttachStateChangeListener() के लिए सेटर तरीके के बजाय OnAttachStateChangeListener. android.databinding.adapters.ListenerUtil क्लास इन्हें ट्रैक करने में मदद करती है लिसनर ताकि उन्हें बाइंडिंग अडैप्टर से हटाया जा सके.

ऑब्जेक्ट कन्वर्ज़न

ऑब्जेक्ट को अपने-आप बदलने की सुविधा

जब बाइंडिंग से Object मिलता है एक्सप्रेशन, लाइब्रेरी प्रॉपर्टी. Object को चुने गए तरीके के पैरामीटर टाइप में कास्ट किया जाता है. यह का इस्तेमाल करने वाले ऐप्लिकेशन में सुविधाजनक तरीके से काम करना आसान बनाता है ObservableMap क्लास को डेटा स्टोर करें, जैसा कि नीचे दिए गए उदाहरण में दिखाया गया है:

<TextView
   android:text='@{userMap["lastName"]}'
   android:layout_width="wrap_content"
   android:layout_height="wrap_content" />

एक्सप्रेशन में userMap ऑब्जेक्ट, ऐसी वैल्यू दिखाता है जो अपने-आप होती है पैरामीटर टाइप में कास्ट करने के लिए, setText(CharSequence) तरीके का इस्तेमाल किया जाता है, जिसकी मदद से android:text एट्रिब्यूट की वैल्यू सेट करें. अगर पैरामीटर टाइप तो एक्सप्रेशन में रिटर्न टाइप को कास्ट करें.

कस्टम कन्वर्ज़न

कुछ मामलों में, अलग-अलग तरह के डेटा के बीच कस्टम कन्वर्ज़न की ज़रूरत होती है. इसके लिए उदाहरण के लिए, किसी व्यू के android:background एट्रिब्यूट के लिए Drawable होना चाहिए, लेकिन color मान एक पूर्णांक है. नीचे दिए गए उदाहरण में, एट्रिब्यूट के लिए Drawable होना चाहिए, लेकिन इसके बजाय पूर्णांक दिया जाता है:

<View
   android:background="@{isError ? @color/red : @color/white}"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>

जब भी Drawable की उम्मीद हो और पूर्णांक दिखे, तो int को बदलें ColorDrawable के लिए. कन्वर्ज़न करने के लिए, BindingConversion एनोटेशन नीचे दिया गया है:

Kotlin

@BindingConversion
fun convertColorToDrawable(color: Int) = ColorDrawable(color)

Java

@BindingConversion
public static ColorDrawable convertColorToDrawable(int color) {
    return new ColorDrawable(color);
}

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

// The @drawable and @color represent different value types in the same
// expression, which causes a build error.
<View
   android:background="@{isError ? @drawable/error : @color/white}"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>

अन्य संसाधन

डेटा बाइंडिंग के बारे में ज़्यादा जानने के लिए, इन संसाधनों को देखें.

सैंपल

कोड लैब

ब्लॉग पोस्ट