क्या मुझे एंड्रॉइड पर दुश्मनी का उपयोग करने से सख्ती से बचना चाहिए?


92

मैं Bundleनीचे दिए गए इंटरफ़ेस की तरह एक साथ संबंधित स्थिरांक की एक कुंजी को परिभाषित करता था :

public interface From{
    String LOGIN_SCREEN = "LoginSCreen";
    String NOTIFICATION = "Notification";
    String WIDGET = "widget";
}

यह मुझे एक साथ संबंधित स्थिरांक के लिए एक अच्छा तरीका प्रदान करता है और एक स्थिर आयात (लागू नहीं) करके उनका उपयोग करता है। मुझे पता है कि Androidफ्रेमवर्क भी उसी तरह से स्थिरांक का उपयोग करता है Toast.LENTH_LONG, जैसे View.GONE

हालांकि, मुझे अक्सर लगता है कि Java Enumsनिरंतर का प्रतिनिधित्व करने के लिए बहुत बेहतर और शक्तिशाली तरीका प्रदान करता है।

लेकिन क्या उपयोग enumsकरने में एक समस्या है Android?

थोड़े से शोध के साथ मैं भ्रम में समाप्त हो गया। इस प्रश्न से "एंड्रॉइड से बचने के लिए आपको केवल इनट्स की आवश्यकता कहां है" एंड्रॉइड के प्रदर्शन युक्तियों से हटा दिया गया है; यह स्पष्ट है कि इसके प्रदर्शन सुझावों से "एनम से बचें"Google हटा दिया गया है , लेकिन इससे आधिकारिक प्रशिक्षण डॉक्स मेमोरी ओवरहेड अनुभाग से अवगत रहें यह स्पष्ट रूप से कहता है: "एनम अक्सर स्थैतिक स्थिरांक के रूप में दो बार से अधिक स्मृति की आवश्यकता होती है। आपको एंड्रॉइड पर एनम का उपयोग करने से सख्ती से बचना चाहिए। " क्या यह अभी भी अच्छा है? ( 1.6 के बाद संस्करणों में कहें )Java

एक और मुद्दा यह है कि मैंने देखा भेजने के लिए है enumsभर में intentsउपयोग करते हुए Bundleमैं उन्हें serializing द्वारा भेजना चाहिए (यानी putSerializable(), कि मैं एक महंगी आपरेशन आदिम की तुलना में लगता है कि putString()विधि, eventhough enumsमुक्त करने के लिए यह प्रदान करता है)।

क्या कोई यह स्पष्ट कर सकता है कि कौन सा एक सबसे अच्छा तरीका है Android? क्या मुझे इसका उपयोग enumsकरने से सख्ती से बचना चाहिए Android?


5
आपको उन उपकरणों का उपयोग करना चाहिए जो आपके पास उपलब्ध हैं। वास्तव में, एक गतिविधि या टुकड़ा बहुत सी मेमोरी और सीपीयू का उपयोग करता है, लेकिन इसका उपयोग बंद करने का कोई कारण नहीं है। स्थैतिक int का उपयोग करें यदि आपको केवल उसी की आवश्यकता है, और जब आपको आवश्यकता हो तो enums का उपयोग करें।
पैट्रिक

11
मैं सहमत हूँ। यह समय से पहले अनुकूलन की तरह बदबू आ रही है। जब तक आप एक प्रदर्शन और / या स्मृति समस्या नहीं रखते हैं, और प्रोफाइलिंग के माध्यम से साबित कर सकते हैं कि दुश्मनी का कारण है, उनका उपयोग करें जहां यह समझ में आता है।
ग्रेबियरगेड गीक

2
यह माना जाता था कि एनम गैर-ट्राइबल प्रदर्शन जुर्माना लगाते थे, लेकिन अधिक हाल के बेंचमार्क इसके बजाय स्थिरांक का उपयोग करने के लिए कोई लाभ नहीं दिखाते हैं। देखें stackoverflow.com/questions/24491160/… साथ ही stackoverflow.com/questions/5143256/…
बेंजामिन सर्जेंट

1
एक बंडल में एक एनम को क्रमबद्ध करने के प्रदर्शन के दंड से बचने के लिए, आप इसे एक इंट के Enum.ordinal()बजाय पास कर सकते हैं ।
ब्लेडडॉकर

1
अंत में Enum पर प्रदर्शन की समस्याओं के बारे में कुछ स्पष्टीकरण दिए गए हैं youtube.com/watch?v=Hzs6OBcvNQE
nvinayshetty

जवाबों:


115

enumजब आपको इसकी विशेषताओं की आवश्यकता हो तब उपयोग करें । इसे सख्ती से न बचें

जावा एनम अधिक शक्तिशाली है, लेकिन अगर आपको इसकी विशेषताओं की आवश्यकता नहीं है, तो स्थिरांक का उपयोग करें, वे कम जगह घेरते हैं और वे स्वयं ही आदिम हो सकते हैं।

एनम का उपयोग कब करें:

  • जाँच टाइप - आप स्वीकार कर सकते हैं केवल सूचीबद्ध मानों, और वे निरंतर नहीं हैं (क्या मैं फोन नीचे देखें निरंतर यहाँ)
  • ओवरलोडिंग का तरीका - हर एनम स्थिरांक का अपना तरीका है

    public enum UnitConverter{
        METERS{
            @Override
            public double toMiles(final double meters){
                return meters * 0.00062137D;
            }
    
            @Override
            public double toMeters(final double meters){
                return meters;
            }
        },
        MILES{
            @Override
            public double toMiles(final double miles){
                return miles;
            }
    
            @Override
            public double toMeters(final double miles){
                return miles / 0.00062137D;
            }
        };
    
        public abstract double toMiles(double unit);
        public abstract double toMeters(double unit);
    }
  • अधिक डेटा - आपके एक स्थिरांक में एक से अधिक जानकारी होती है जिसे एक चर में नहीं डाला जा सकता है

  • जटिल डेटा - डेटा पर काम करने के लिए आपकी निरंतर ज़रूरत के तरीके

जब एनम का उपयोग नहीं करना है:

  • आप एक प्रकार के सभी मूल्यों को स्वीकार कर सकते हैं, और आपके स्थिरांक में केवल इन सबसे अधिक उपयोग किया जाता है
  • आप निरंतर डेटा को स्वीकार कर सकते हैं

    public class Month{
        public static final int JANUARY = 1;
        public static final int FEBRUARY = 2;
        public static final int MARCH = 3;
        ...
    
        public static String getName(final int month){
            if(month <= 0 || month > 12){
                throw new IllegalArgumentException("Invalid month number: " + month);
            }
    
            ...
        }
    }
  • नामों के लिए (जैसे आपके उदाहरण में)
  • बाकी सब के लिए जो वास्तव में एक एनम की जरूरत नहीं है

एनम अधिक स्थान घेरते हैं

  • एक एनम निरंतर के लिए एक एकल संदर्भ 4 बाइट्स रखता है
  • प्रत्येक enum स्थिरांक उस स्थान को घेरता है जो ऑब्जेक्ट के 8 बाइट्स + ओवरहेड से जुड़े अपने खेतों के आकार का एक योग है
  • enum वर्ग खुद कुछ जगह घेरता है

लगातार कम जगह घेरते हैं

  • एक स्थिरांक में एक संदर्भ नहीं होता है, इसलिए यह एक शुद्ध डेटा है (भले ही यह एक संदर्भ हो, तो एनम उदाहरण अन्य संदर्भ का संदर्भ होगा)
  • स्थिरांक को एक मौजूदा वर्ग में जोड़ा जा सकता है - दूसरी कक्षा को जोड़ना आवश्यक नहीं है
  • स्थिरांक का झुकाव हो सकता है; यह विस्तारित संकलन-समय सुविधाएँ लाता है (जैसे अशक्त जाँच, मृत कोड खोजना आदि)

2
आप इंट कॉन्स्टेंट के लिए प्रकार की जाँच अनुकरण करने के लिए @IntDef एनोटेशन का उपयोग कर सकते हैं। यह जावा एनम के पक्ष में एक कम तर्क है।
ब्लेडकारोड

3
@BladeCoder नहीं, आपको निरंतरता के लिए संदर्भ की आवश्यकता नहीं है
कामिल जारोज़

1
इसके अलावा, यह नोट करना अच्छा है कि एनम का उपयोग प्रतिबिंब के उपयोग को बढ़ावा देता है। और यह ज्ञात है कि प्रतिबिंब का उपयोग Android के लिए एक बड़ा प्रदर्शन हिट है। यहाँ देखें: blog.nimbledroid.com/2016/02/23/slow-Android-reflection.html
w3bshark

3
@ w3bshark प्रतिबिंब के उपयोग को कैसे बढ़ावा देते हैं?
केविन क्रुमविडे

3
एक और बात ध्यान में रखना है कि मानक खाली से एक ढेर डंप है "हैलो, दुनिया!" परियोजना में 4,000 से अधिक वर्ग और 700,000 वस्तुएं शामिल हैं। यहां तक ​​कि अगर आपके पास हज़ारों स्थिरांक के साथ एक बहुत बड़ा वातावरण है, तो आप सुनिश्चित कर सकते हैं कि प्रदर्शन प्रभाव एंड्रॉइड फ्रेमवर्क के ब्लोट के बगल में नगण्य होगा।
केविन क्रुमविडे

57

यदि एनमों में केवल मान हैं, तो आपको IntDef / StringDef का उपयोग करने का प्रयास करना चाहिए, जैसा कि यहाँ दिखाया गया है:

https://developer.android.com/studio/write/annotations.html#enum-annotations

उदाहरण: इसके बजाय:

enum NavigationMode {NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS} 

तुम इस्तेमाल:

@IntDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS})
@Retention(RetentionPolicy.SOURCE)
public @interface NavigationMode {}

public static final int NAVIGATION_MODE_STANDARD = 0;
public static final int NAVIGATION_MODE_LIST = 1;
public static final int NAVIGATION_MODE_TABS = 2;

और उस फ़ंक्शन में जिसके पास पैरामीटर / लौटाया गया मान है, का उपयोग करें:

@NavigationMode
public abstract int getNavigationMode();

public abstract void setNavigationMode(@NavigationMode int mode);

यदि एनम जटिल है, तो एनम का उपयोग करें। इतना खराब नहीं है।

निरंतर मूल्यों बनाम एनमों की तुलना करने के लिए, आपको यहां पढ़ना चाहिए:

http://hsc.com/Blog/Best-Practices-For-Memory-Optimization-on-Android-1

उनका उदाहरण 2 मूल्यों वाले एक एनम का है। निरंतर पूर्णांक का उपयोग करने पर 128 बाइट की तुलना में डेक्स फ़ाइल में 1112 बाइट्स लगते हैं। समझ में आता है, जैसा कि एनम असली वर्ग हैं, यह सी / सी ++ पर कैसे काम करता है, इसके विपरीत।


हालाँकि, मैं अन्य जवाबों की सराहना करता हूं, जो कि एनमोंस के पेशेवरों / विपक्षों को प्रदान करते हैं, यह उत्तर स्वीकृत उत्तर होना चाहिए क्योंकि यह विशेष रूप से एंड्रॉइड के लिए सबसे अच्छा समाधान प्रदान करता है। समर्थन एनोटेशन जाने का रास्ता है। हम, जैसा कि एंड्रॉइड डेवलपर्स सोच रहे हैं "जब तक मेरे पास एनमों का उपयोग करने का एक मजबूत कारण नहीं है, तब तक मैं एनोटेशन के साथ स्थिरांक का उपयोग करूंगा", अन्य उत्तरों के 'सोचने के तरीके' के बजाय "जब तक मैं बाद में स्मृति / प्रदर्शन के बारे में चिंतित नहीं होना शुरू करता हूं," मैं एनम का उपयोग कर सकता हूं ”। बाद में प्रदर्शन की समस्या होने से खुद को रोकें!
w3bshark

3
@ w3bshark यदि आपको प्रदर्शन की समस्या हो रही है, तो एनमों पहली चीज़ होने की संभावना नहीं है कि आपको उन्हें हल करने के बारे में सोचना चाहिए। एनोटेशन के अपने ट्रेड-ऑफ हैं: उनके पास संकलक समर्थन नहीं है, उनके पास अपने क्षेत्र और विधियां नहीं हो सकती हैं, वे लिखने के लिए थकाऊ हैं, आप आसानी से एक इंट, और इसी तरह एनोटेट करना भूल सकते हैं। वे समग्र रूप से एक बेहतर समाधान नहीं हैं, वे बस जरूरत पड़ने पर हीप स्पेस को बचाने के लिए हैं।
मैल्कम

1
@androiddeveloper enum घोषणापत्र में परिभाषित नहीं निरंतर गुजरने से आप गलती नहीं कर सकते। यह कोड कभी संकलित नहीं होगा। यदि आप एक IntDefएनोटेशन के साथ गलत कंटिन्यू पास करते हैं , तो यह होगा। घड़ियों के रूप में, मुझे लगता है कि यह बहुत स्पष्ट है। किस डिवाइस में अधिक सीपीयू पावर, रैम और बैटरी है: एक फोन या एक घड़ी? और किन लोगों को सॉफ्टवेयर की आवश्यकता है क्योंकि प्रदर्शन के लिए उन्हें अधिक अनुकूलित होना चाहिए?
मैल्कम

3
@androiddeveloper ठीक है, यदि आप सख्त शब्दावली पर जोर देते हैं, तो गलतियों से मेरा मतलब था कि त्रुटियां जो संकलन-समय की त्रुटियां नहीं हैं (रन-टाइम या प्रोग्राम-लॉजिक त्रुटियां)। क्या आप मुझे ट्रोल कर रहे हैं या वास्तव में उनके और संकलन-समय त्रुटियों के लाभों के बीच अंतर नहीं है? यह एक अच्छी तरह से चर्चा का विषय है, इसे वेब पर देखें। घड़ियों के बारे में, एंड्रॉइड में अधिक डिवाइस शामिल हैं, लेकिन सबसे अधिक विवश लोग सबसे कम सामान्य भाजक होंगे।
मैल्कम

2
@androiddeveloper मैंने पहले ही उन दोनों कथनों का जवाब दिया है, उन्हें एक बार फिर से दोहराते हुए मैंने जो कहा उसे अमान्य नहीं करता।
मैल्कम

12

पिछले उत्तरों के अलावा, मैं यह भी जोड़ूंगा कि यदि आप Proguard का उपयोग कर रहे हैं (और आपको निश्चित रूप से इसे आकार कम करने और अपने कोड को बाधित करने के लिए करना चाहिए), तो आपका Enumsस्वचालित रूप से @IntDefजहाँ कहीं भी संभव हो, में परिवर्तित हो जाएगा :

https://www.guardsquare.com/en/proguard/manual/optimizations

वर्ग / unboxing / enum

जब भी संभव हो, पूर्णांक स्थिरांक के लिए enum प्रकार को सरल करता है।

इसलिए, यदि आपके पास कुछ असतत मूल्य हैं और किसी विधि को केवल इस मान को लेने की अनुमति दी जानी चाहिए, न कि अन्य प्रकार के। Enum , क्योंकि प्रोगार्ड मेरे लिए कोड के अनुकूलन का यह मैनुअल काम करेगा।

तथा यहां जेक व्हार्टन से एनम का उपयोग करने के बारे में एक अच्छी पोस्ट है, इस पर एक नज़र डालें।

एक लाइब्रेरी डेवलपर के रूप में, मैं इन छोटे अनुकूलन को पहचानता हूं जो हमें करना चाहिए क्योंकि हम उपभोग ऐप के आकार, स्मृति और प्रदर्शन पर जितना संभव हो उतना कम प्रभाव डालना चाहते हैं। लेकिन यह महसूस करना महत्वपूर्ण है कि [...] अपने सार्वजनिक एपीआई बनाम पूर्णांक मानों में एक एंम लगाते हैं जहां उपयुक्त पूरी तरह से ठीक है। सूचित निर्णय लेने के लिए अंतर जानना महत्वपूर्ण है


11

क्या मुझे एंड्रॉइड पर दुश्मनी का उपयोग करने से सख्ती से बचना चाहिए?

नहीं। " सख्ती से " का मतलब है कि वे बहुत बुरे हैं, उनका उपयोग बिल्कुल नहीं किया जाना चाहिए। संभवतः एक प्रदर्शन की समस्या एक चरम स्थिति में उत्पन्न हो सकती है जैसे कि कई कई (हजारों या लाखों) ऑपरेशन एनम के साथ (लगातार ui थ्रेड पर)। अधिक सामान्य नेटवर्क I / O ऑपरेशन हैं जो पृष्ठभूमि थ्रेड में कड़ाई से होने चाहिए । एनम का सबसे आम उपयोग शायद कुछ प्रकार की जांच है - चाहे कोई वस्तु यह हो या जो इतनी तेज़ हो कि आप किसी भी एनम की तुलना और पूर्णांक की तुलना के बीच अंतर नहीं देख पाएंगे।

क्या कोई यह स्पष्ट कर सकता है कि Android में उसी का प्रतिनिधित्व करने का सबसे अच्छा तरीका कौन सा है?

इसके लिए अंगूठे का कोई सामान्य नियम नहीं है। आपके लिए जो भी काम करता है उसका उपयोग करें और आपको अपना ऐप तैयार करने में मदद करता है। बाद में ऑप्टिमाइज़ करें - आपके नोटिस करने के बाद एक अड़चन है जो आपके ऐप के कुछ पहलू को धीमा कर देती है।


1
आप बाद में ऑप्टिमाइज़ क्यों करेंगे, जब समर्थन एनोटेशन के साथ स्थिरांक का उपयोग करना केवल इतना आसान है और अब अनुकूलित करें? यहाँ देखें @ android_developer का उत्तर।
w3bshark

11

Android P के साथ, google को enums का उपयोग करने में कोई प्रतिबंध / आपत्ति नहीं है

प्रलेखन बदल गया है जहां पहले सतर्क होने की सिफारिश की गई थी, लेकिन अब इसका उल्लेख नहीं करता है। https://developer.android.com/reference/java/lang/Enum


1
क्या इसके अलावा कोई और सबूत है: मैंने @JakeWharton के बारे में बयान पाया कि: twitter.com/jakewharton/status/1067790191237181441 । कोई भी व्यक्ति बायोटेक की जांच कर सकता है।
सोशियल

4

दो तथ्य।

1, Enum JAVA में सबसे शक्तिशाली विशेषता में से एक है।

2, एंड्रॉइड फोन में आमतौर पर बहुत सारी मेमोरी होती है।

तो मेरा जवाब है नहीं। मैं एंड्रॉइड में Enum का उपयोग करूंगा।


2
यदि एंड्रॉइड में बहुत सारी मेमोरी है, तो इसका मतलब यह नहीं है कि आपके ऐप को इसका उपभोग करना चाहिए और दूसरों के लिए कुछ भी नहीं छोड़ना चाहिए। एंड्रॉइड ओएस द्वारा अपने ऐप को मारे जाने से बचाने के लिए आपको सर्वोत्तम प्रथाओं का पालन करना चाहिए। मैं यह नहीं कह रहा हूं कि एनम का उपयोग न करें, लेकिन केवल तभी उपयोग करें जब आपके पास कोई विकल्प न हो।
वरुंडोइड

1
मैं आपसे सहमत हूं कि हमें सर्वोत्तम अभ्यास का पालन करना चाहिए, हालांकि, सबसे अच्छा अभ्यास का मतलब हमेशा कम से कम मेमोरी का उपयोग करना नहीं होता है। कोड को साफ रखना, समझने में आसान है, कई k मेमोरी को सेव करने से ज्यादा महत्वपूर्ण है। आपको एक संतुलन खोजने की जरूरत है।
काई वांग

1
मैं आपसे सहमत हूं कि हमें एक संतुलन खोजने की आवश्यकता है, लेकिन TypeDef का उपयोग करने से हमारा कोड खराब या कम रख-रखाव वाला नहीं है। मैं इसे एक वर्ष से अधिक समय से उपयोग कर रहा हूं और ऐसा कभी नहीं महसूस किया कि मेरे कोड को समझना आसान नहीं है, मेरे किसी भी साथी ने कभी यह शिकायत नहीं की कि टाइपडिफ्स को एनम की तुलना में समझना मुश्किल है। मेरी सलाह है कि जब आप के पास कोई दूसरा विकल्प न हो तो केवल एनम का उपयोग करें।
वरुणोदय

2

मुझे यह जोड़ना पसंद है, कि जब आप सूची <> या मानचित्र <> घोषित करते हैं, तो आप @ नोट का उपयोग नहीं कर सकते, जहाँ कुंजी या मान आपके एनोटेशन इंटरफेस में से एक है। आपको त्रुटि मिलती है "एनोटेशन की अनुमति नहीं है यहाँ"।

enum Values { One, Two, Three }
Map<String, Values> myMap;    // This works

// ... but ...
public static final int ONE = 1;
public static final int TWO = 2;
public static final int THREE = 3;

@Retention(RetentionPolicy.SOURCE)
@IntDef({ONE, TWO, THREE})
public @interface Values {}

Map<String, @Values Integer> myMap;    // *** ERROR ***

इसलिए जब आपको इसे एक सूची / मानचित्र में पैक करने की आवश्यकता होती है, तो एनम का उपयोग करें, क्योंकि उन्हें जोड़ा जा सकता है, लेकिन @annotated int / string group नहीं कर सकते।

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