क्या मुझे Android कस्टम दृश्य के लिए सभी तीन निर्माणकर्ताओं की आवश्यकता है?


143

एक कस्टम दृश्य बनाते समय, मैंने देखा है कि बहुत से लोग इसे इस तरह करते हैं:

public MyView(Context context) {
  super(context);
  // this constructor used when programmatically creating view
  doAdditionalConstructorWork();
}

public MyView(Context context, AttributeSet attrs) {
  super(context, attrs);
  // this constructor used when creating view through XML
  doAdditionalConstructorWork();
}

private void doAdditionalConstructorWork() {

  // init variables etc.
}

मेरा पहला सवाल यह है कि कंस्ट्रक्टर के बारे में क्या MyView(Context context, AttributeSet attrs, int defStyle)? मुझे यकीन नहीं है कि यह कहाँ उपयोग किया जाता है, लेकिन मैं इसे सुपर क्लास में देखता हूं। क्या मुझे इसकी आवश्यकता है, और इसका उपयोग कहां किया जाता है?

इस सवाल का एक और हिस्सा है

जवाबों:


144

यदि आप अपने रिवाज Viewको xmlभी इस तरह से जोड़ देंगे :

 <com.mypack.MyView
      ...
      />

आपको कंस्ट्रक्टर की आवश्यकता होगी public MyView(Context context, AttributeSet attrs), अन्यथा Exceptionएंड्रॉइड आपके द्वारा फुलाए जाने पर आपको मिलेगा View

यदि आप अपने Viewसे जोड़ते xmlहैं और android:styleविशेषता भी निर्दिष्ट करते हैं:

 <com.mypack.MyView
      style="@styles/MyCustomStyle"
      ...
      />

MyCustomStyleस्पष्ट एक्सएमएल विशेषताओं को लागू करने से पहले 2 निर्माणकर्ता को भी बुलाया जाएगा और शैली को डिफ़ॉल्ट किया जाएगा ।

तीसरे कंस्ट्रक्टर का उपयोग आमतौर पर तब किया जाता है जब आप एक ही शैली के लिए अपने आवेदन में सभी दृश्य चाहते हैं।


3
पहले कंस्ट्रक्टर का उपयोग कब करें?
एंड्रॉयड किलर

@OvidiuLatcu क्या आप तीसरे CTOR (3 मापदंडों के साथ) का उदाहरण दिखा सकते हैं?
एंड्रॉइड डेवलपर

क्या मैं कंस्ट्रक्टर में अतिरिक्त पैरामीटर जोड़ सकता हूं और मैं उनका उपयोग कैसे कर सकता हूं?
मोहम्मद सुबी शेख कुरुश

24
तीसरे निर्माणकर्ता के बारे में, यह वास्तव में पूरी तरह से गलत है । XML हमेशा दो-तर्क निर्माता को कॉल करता है। तीन-तर्क (और चार-तर्क ) कंस्ट्रक्टर को उपवर्गों द्वारा बुलाया जाता है यदि वे एक विशेषता को डिफ़ॉल्ट शैली, या एक डिफ़ॉल्ट शैली को सीधे निर्दिष्ट करना चाहते हैं (चार-तर्क निर्माता के मामले में)
imgx64

मैंने उत्तर को सही बनाने के लिए एक संपादन प्रस्तुत किया। मैंने नीचे एक वैकल्पिक उत्तर भी प्रस्तावित किया है।
मैबिनिन

118

यदि आप सभी तीन कंस्ट्रक्टर्स को ओवरराइड करते हैं, तो कृपया कैस्केड this(...)कॉल न करें। आपको इसके बजाय ऐसा करना चाहिए:

public MyView(Context context) {
    super(context);
    init(context, null, 0);
}

public MyView(Context context, AttributeSet attrs) {
    super(context,attrs);
    init(context, attrs, 0);
}

public MyView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init(context, attrs, defStyle);
}

private void init(Context context, AttributeSet attrs, int defStyle) {
    // do additional work
}

इसका कारण यह है कि मूल श्रेणी में अपने स्वयं के निर्माणकर्ताओं में डिफ़ॉल्ट विशेषताएँ शामिल हो सकती हैं जिन्हें आप गलती से ओवरराइड कर रहे होंगे। उदाहरण के लिए, यह इसके लिए निर्माता है TextView:

public TextView(Context context) {
    this(context, null);
}

public TextView(Context context, @Nullable AttributeSet attrs) {
    this(context, attrs, com.android.internal.R.attr.textViewStyle);
}

public TextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    this(context, attrs, defStyleAttr, 0);
}

यदि आप कॉल नहीं करते हैं super(context), तो आप R.attr.textViewStyleस्टाइल एट्री के रूप में ठीक से सेट नहीं होंगे ।


12
सूची दृश्य का विस्तार करते समय यह आवश्यक सलाह है। इस कैस्केडिंग के ऊपर (पिछले) प्रशंसक के रूप में, मुझे याद है कि एक सूक्ष्म बग नीचे ट्रैकिंग घंटे खर्च करते हैं जो तब चले गए जब मैंने प्रत्येक कंस्ट्रक्टर के लिए सही सुपर विधि कहा।
ग्रूवी ६०

BTW @Jin मैंने इस उत्तर में कोड का उपयोग किया है: stackoverflow.com/a/22780035/294884 जो आपके उत्तर पर आधारित लगता है - लेकिन ध्यान दें कि लेखक में इन्फ्लेटर का उपयोग शामिल है?
फेटी

1
मैं यह है आवश्यक नहीं सभी निर्माताओं में init कॉल करने के लिए, क्योंकि जब आप कॉल पदानुक्रम का पालन करें, आप कार्यक्रम संबंधी दृश्य निर्माण वैसे भी देखें (संदर्भ संदर्भ) के लिए डिफ़ॉल्ट निर्माता में खत्म हो जाएगा {} लगता है
मैरिएन Klühspies

im वही कर रहा है, लेकिन
पाठ्य

1
मुझे यह कभी कैसे पता चला?
Suragch

49

MyView (संदर्भ संदर्भ)

प्रोग्राम के दौरान दृश्य को अस्थिर करते समय उपयोग किया जाता है।

माईव्यू (संदर्भ संदर्भ, गुणनिष्ठ गुण)

LayoutInflaterXml विशेषताएँ लागू करने के लिए उपयोग किया जाता है । यदि इस विशेषता में से एक का नाम है style, तो लेआउट xml फ़ाइल में स्पष्ट मानों की तलाश करने से पहले विशेषताओं को शैली में देखा जाएगा।

माईव्यू (संदर्भ संदर्भ, एटिट्यूड अटार्स, इंट डिफाइटल एटर)

मान लें कि आप styleप्रत्येक लेआउट फ़ाइल में निर्दिष्ट किए बिना सभी विजेट के लिए एक डिफ़ॉल्ट शैली लागू करना चाहते हैं । एक उदाहरण के लिए सभी चेकबॉक्स को डिफ़ॉल्ट रूप से गुलाबी करें। आप इसे डिफॉल्टलेक्टर के साथ कर सकते हैं और फ्रेमवर्क आपके विषय में डिफ़ॉल्ट शैली को खोजेगा।

ध्यान दें कि कुछ समय पहले defStyleAttrगलत तरीके से नामित किया गया defStyleथा और इस बारे में कुछ चर्चा है कि क्या इस निर्माणकर्ता की वास्तव में आवश्यकता है या नहीं। Https://code.google.com/p/android/issues/detail?id=12683 देखें

माईव्यू (संदर्भ संदर्भ, एटिट्यूड एटसेट्स, इंट डिफाइटल एटर, इंट डिफाइटलइएस)

यदि आप अनुप्रयोगों के आधार विषय पर नियंत्रण रखते हैं, तो तीसरा निर्माता अच्छा काम करता है। यह Google के लिए काम कर रहा है क्योंकि वे डिफ़ॉल्ट विजेट्स के साथ अपने विजेट्स को शिप करते हैं। लेकिन मान लीजिए कि आप एक विजेट लाइब्रेरी लिख रहे हैं और आप चाहते हैं कि आपके उपयोगकर्ताओं को बिना थीम के ट्विस्ट करने के लिए एक डिफ़ॉल्ट शैली सेट की जाए। अब आप defStyleResइसे 2 पहले कंस्ट्रक्टर में डिफ़ॉल्ट मान पर सेट करके उपयोग कर सकते हैं :

public MyView(Context context) {
  super(context, null, 0, R.style.MyViewStyle);
  init();
}

public MyView(Context context, AttributeSet attrs) {
  super(context, attrs, 0, R.style.MyViewStyle);
  init();
}

सब मिलाकर

यदि आप अपने स्वयं के विचारों को लागू कर रहे हैं, तो केवल 2 पहले निर्माणकर्ताओं की आवश्यकता होनी चाहिए और उन्हें रूपरेखा द्वारा बुलाया जा सकता है।

यदि आप चाहते हैं कि आपके दृश्य एक्स्टेंसिबल हों, तो आप अपने वर्ग के बच्चों के लिए वैश्विक स्टाइलिंग का उपयोग करने में सक्षम होने के लिए 4 वें कंस्ट्रक्टर को लागू कर सकते हैं।

मुझे 3rd कंस्ट्रक्टर के लिए वास्तविक उपयोग का मामला नहीं दिख रहा है। हो सकता है कि एक शॉर्टकट यदि आप अपने विजेट के लिए एक डिफ़ॉल्ट शैली प्रदान नहीं करते हैं, लेकिन फिर भी अपने उपयोगकर्ताओं को ऐसा करने में सक्षम होना चाहते हैं। इतना नहीं होना चाहिए।


7

कोटलिन इस दर्द को दूर करने के लिए लगता है:

class MyView
@JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0)
    : View(context, attrs, defStyle)

@JvmOverloads सभी आवश्यक निर्माणकर्ताओं को उत्पन्न करेगा (देखें कि एनोटेशन के दस्तावेज़ देखें ), जिनमें से प्रत्येक संभवतः सुपर () कहता है। फिर, बस अपनी इनिशियलाइज़ेशन विधि को कोटलिन इनिट {} ब्लॉक से बदलें। बॉयलरप्लेट कोड चला गया!


1

तीसरा कंस्ट्रक्टर बहुत अधिक जटिल है। मुझे एक उदाहरण पकड़ो।

समर्थन-वी 7 SwitchCompactपैकेज 24 संस्करण के बाद से समर्थन thumbTintऔर trackTintविशेषता देता है जबकि 23 संस्करण उनका समर्थन नहीं करते हैं। अब आप उन्हें 23 संस्करण में समर्थन देना चाहते हैं और आप इसे कैसे प्राप्त करेंगे?

हम कस्टम व्यू SupportedSwitchCompactएक्सटेंड्स का इस्तेमाल करते हैं SwitchCompact

public SupportedSwitchCompat(Context context) {
    this(context, null);
}

public SupportedSwitchCompat(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
}

public SupportedSwitchCompat(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init();
}

private void init(){
    mThumbDrawable = getThumbDrawable();
    mTrackDrawable = getTrackDrawable();
    applyTint();
}

यह एक पारंपरिक कोड शैली है। ध्यान दें कि हम यहां से तीसरे परम में 0 पास हैं । जब आप कोड चलाते हैं, तो आपको getThumbDrawable()हमेशा यह पता चलता है कि यह कितना अजीब है क्योंकि यह getThumbDrawable()सुपर क्लास SwitchCompactकी विधि है।

यदि आप R.attr.switchStyleतीसरे परम के पास जाते हैं , तो सब कुछ ठीक हो जाता है। क्यों?

तीसरा परम एक सरल गुण है। विशेषता एक शैली संसाधन की ओर इशारा करती है। उपरोक्त मामले में, सिस्टम को switchStyleवर्तमान थीम में विशेषता मिलेगी सौभाग्य से सिस्टम इसे ढूंढता है।

में frameworks/base/core/res/res/values/themes.xml, आप देखेंगे:

<style name="Theme">
    <item name="switchStyle">@style/Widget.CompoundButton.Switch</item>
</style>

-2

यदि आपको अभी चर्चा के तहत तीन निर्माणकर्ताओं को शामिल करना है, तो आप यह भी कर सकते हैं।

public MyView(Context context) {
  this(context,null,0);
}

public MyView(Context context, AttributeSet attrs) {
  this(context,attrs,0);
}

public MyView(Context context, AttributeSet attrs, int defStyle) {
  super(context, attrs, defStyle);
  doAdditionalConstructorWork();

}

2
@ जो कई मामलों में एक अच्छा विचार है, लेकिन यह कई मामलों में भी सुरक्षित है (जैसे: RelativeLayout, FrameLayout, RecyclerView, आदि)। इसलिए, मैं कहूंगा कि यह संभवतः मामला दर मामला है और कैसकेड का निर्णय करने से पहले बेस क्लास की जाँच की जानी चाहिए या नहीं। अनिवार्य रूप से, यदि बेस क्लास में 2-पैरा कंस्ट्रक्टर सिर्फ इस (संदर्भ, अट्रैक्शन, 0) को कॉल कर रहा है, तो कस्टम व्यू क्लास में भी ऐसा करना सुरक्षित है।
ejw

@IanWong, निश्चित रूप से, यह कहा जाएगा, क्योंकि पहले और दूसरे तरीके तीसरे बुला रहे हैं।
कूलमैन्ड
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.