UI थ्रेड से साझा किए गए साझाकरणों को एक्सेस करना चाहिए?


113

जिंजरब्रेड की रिहाई के साथ, मैं कुछ नए एपीआई के साथ प्रयोग कर रहा हूं, उनमें से एक स्ट्रिक्टमोड है

मैंने देखा कि एक चेतावनी के लिए है getSharedPreferences()

यह चेतावनी है:

StrictMode policy violation; ~duration=1949 ms: android.os.StrictMode$StrictModeDiskReadViolation: policy=23 violation=2

और यह getSharedPreferences()UI थ्रेड पर किए जा रहे कॉल के लिए दिया जा रहा है।

क्या SharedPreferencesयूआई थ्रेड को वास्तव में एक्सेस और परिवर्तन किया जाना चाहिए ?


मैंने हमेशा यूआई थ्रेड पर अपना प्राथमिकता ऑपरेशन किया है। हालांकि मुझे लगता है कि यह समझ में आता है क्योंकि यह एक IO ऑपरेशन है
फालमरी

जवाबों:


184

मुझे खुशी है कि आप पहले से ही इसके साथ खेल रहे हैं!

ध्यान देने योग्य कुछ बातें: (आलसी बुलेट रूप में)

  • यदि यह आपकी समस्याओं में से सबसे खराब है, तो आपके ऐप का शायद अच्छा स्थान है। :) राइट्स आम तौर पर पढ़े जाने की तुलना में धीमे होते हैं, हालांकि, सुनिश्चित करें कि आप साझा किए गए के बजाय SharedPreferenced $ Editor.apply () का उपयोग कर रहे हैं। लागू करें () GB और async में नया है (लेकिन हमेशा सुरक्षित, जीवनचक्र संक्रमणों से सावधान)। आप GB + और कमिट () पर Froyo या नीचे सशर्त रूप से कॉल लागू () पर प्रतिबिंब का उपयोग कर सकते हैं। मैं यह करने के लिए कैसे नमूना कोड के साथ एक ब्लॉगपोस्ट कर रहा हूँ।

लोडिंग के बारे में, हालांकि ...

  • एक बार लोड होने पर, SharedPreferences सिंगललेट और कैश्ड प्रोसेस-वाइड हैं। इसलिए आप इसे जल्द से जल्द लोड करवाना चाहते हैं, इसलिए आपको इसकी आवश्यकता होने से पहले इसे मेमोरी में रखना चाहिए। (यह मानते हुए कि यह छोटा है, जैसा कि आपको होना चाहिए अगर आप SharedPreferences का उपयोग कर रहे हैं, तो एक सरल XML फ़ाइल ...) आप भविष्य में इसे गलत नहीं करना चाहते हैं जब कोई उपयोगकर्ता एक बटन क्लिक करता है।

  • लेकिन जब भी आप reference.getSaringPreferences (...) को कॉल करते हैं, तो बैकिंग XML फ़ाइल यह देखने के लिए स्टैटिक है कि क्या यह बदल गया है, इसलिए आप वैसे भी UI इवेंट्स के दौरान उन आँकड़ों से बचना चाहेंगे। एक आम तौर पर एक उपवास होना चाहिए (और अक्सर कैश्ड), लेकिन यॉफ़स में कंसिस्टेंसी (और बहुत सारे एंड्रॉइड डिवाइस यफ पर चलते हैं ... Droid, Nexus One इत्यादि) में बहुत ज्यादा नहीं है, इसलिए यदि आप डिस्क से बचते हैं , आप अन्य इन-फ्लाइट या लंबित डिस्क संचालन के पीछे फंसने से बचते हैं।

  • इसलिए आप संभवतः अपने ऑनक्रिएट () के दौरान शेयर्डप्रिफरेंस को लोड करना चाहते हैं और स्टेट को टालते हुए एक ही इंस्टेंस को फिर से इस्तेमाल कर सकते हैं।

  • लेकिन अगर आपको onCreate () के दौरान किसी भी तरह से आपकी प्राथमिकताओं की आवश्यकता नहीं है, तो लोडिंग समय आपके ऐप के स्टार्ट-अप को अनावश्यक रूप से रोक रहा है, इसलिए आमतौर पर FutureTask <SharedPreferences> उपवर्ग जैसा कुछ होना बेहतर होता है जो नए थ्रेड को बंद करने के लिए शुरू होता है। () FutureTask उपवर्ग का मूल्य। फिर जब भी आपको आवश्यकता हो अपने FutureTask <SharedPreferences> के सदस्य को देखें और इसे (।) करें। मैं इसे पारदर्शी रूप से हनीकॉम्ब में पर्दे के पीछे मुक्त बनाने की योजना बनाता हूं। मैं कुछ नमूना कोड जारी करने की कोशिश करूंगा जो इस क्षेत्र में सर्वोत्तम प्रथाओं को दर्शाता है।

आने वाले सप्ताह में स्ट्रिक्टमोड-संबंधित विषयों पर आगामी पोस्ट के लिए एंड्रॉइड डेवलपर्स ब्लॉग की जांच करें।


वाह, स्रोत से सीधे इस तरह के एक स्पष्ट जवाब पाने की उम्मीद नहीं थी! बहुत धन्यवाद!
कपासबेलपॉज़

9
इस अद्भुत पोस्ट के नए पाठकों के लाभ के लिए, @Brad Fitzpatrick: Android डेवलपर के ब्लॉग पोस्ट ब्रैड द्वारा सख्त मोड पर ऊपर उल्लिखित ब्लॉग पोस्ट के लिंक के नीचे खोजें । पोस्ट में साझाकरण के भंडारण के लिए Android संस्करण के आधार पर लागू (जिंजरब्रेड आगे से) या प्रतिबद्ध (froyo) का उपयोग करने के लिए नमूना कोड का लिंक भी है: [सशर्त रूप से उपयोग लागू करें या प्रतिबद्ध] ( code.google.com/p/zippy-android) / स्रोत / ब्राउज़ / ट्रंक / उदाहरण /… )
tony m

4
क्या यह अभी भी ICS \ JB पर प्रासंगिक है?
ekatz

5

साझा प्राथमिकताओं तक पहुंचने में काफी समय लग सकता है क्योंकि उन्हें फ्लैश स्टोरेज से पढ़ा जाता है। क्या तुम बहुत पढ़ते हो? हो सकता है कि आप एक अलग प्रारूप का उपयोग कर सकते हैं, उदाहरण के लिए SQLite डेटाबेस।

लेकिन सब कुछ आप StrictMode का उपयोग कर ठीक नहीं है। या प्रलेखन उद्धृत करने के लिए:

लेकिन सब कुछ तय करने के लिए मजबूर महसूस न करें जो स्ट्रिक्टमोड पाता है। विशेष रूप से, सामान्य गतिविधि जीवनचक्र के दौरान डिस्क एक्सेस के कई मामले अक्सर आवश्यक होते हैं। स्ट्रिक्टमोड का उपयोग उन चीजों को खोजने के लिए करें, जो आपने दुर्घटना से की थीं। यूआई थ्रेड पर नेटवर्क अनुरोध लगभग हमेशा एक समस्या है, हालांकि।


6
लेकिन SQLite भी एक फ़ाइल नहीं है जिसे फ्लैश स्टोरेज से पढ़ा जाना चाहिए - लेकिन एक प्राथमिकता वाली फ़ाइल की तुलना में एक बड़ा और अधिक जटिल। मैं यह मान रहा हूँ कि, वरीयताओं के साथ जुड़े डेटा की मात्रा के लिए, एक प्राथमिकता फ़ाइल तब एक SQLite डेटाबेस बहुत तेज़ होगी।
टॉम

यह सही है। जैसा कि ब्रैड ने पहले ही उल्लेख किया है, यह लगभग हमेशा कोई समस्या नहीं है - और उन्होंने यह भी उल्लेख किया है कि यह एक अच्छा विचार है कि एक बार शेयर्डप्रिफरेंस को लोड करें (हो सकता है कि फ्यूचरटैस्क का उपयोग करके थ्रेड में भी) और एकल उदाहरण के लिए किसी भी संभावित पहुंच के लिए इसे पकड़ कर रखें।
मैरिटेल

5

ब्रैड के उत्तर के बारे में एक सूक्ष्मता: भले ही आप ऑनक्रिएट () में शेयर्डप्रिफरेंस को लोड करते हैं, फिर भी आपको शायद बैकग्राउंड थ्रेड पर मान पढ़ना चाहिए क्योंकि गेटस्ट्रिंग () आदि ब्लॉक फाइल को तब तक पढ़ते हैं जब तक कि फ़ाइनल में साझा की गई फ़ाइल वरीयता (किसी बैकग्राउंड थ्रेड पर) को पढ़ना न हो:

public String getString(String key, String defValue) {
    synchronized (this) {
        awaitLoadedLocked();
        String v = (String)mMap.get(key);
        return v != null ? v : defValue;
    }
}

संपादित () भी उसी तरह से ब्लॉक करता है, हालांकि लागू होता है () अग्रभूमि के धागे पर सुरक्षित दिखाई देता है।

(बीटीडब्ल्यू को यहां डालने के लिए खेद है। मैंने इसे ब्रैड के जवाब के लिए एक टिप्पणी के रूप में दिया होगा, लेकिन मैं अभी शामिल हुआ और ऐसा करने के लिए पर्याप्त प्रतिष्ठा नहीं है।)


1

मुझे पता है कि यह एक पुराना प्रश्न है लेकिन मैं अपना दृष्टिकोण साझा करना चाहता हूं। मेरे पास पढ़ने का समय था और साझा प्राथमिकताओं और वैश्विक अनुप्रयोग वर्ग के संयोजन का उपयोग किया:

ApplicationClass:

public class ApplicationClass extends Application {

    private LocalPreference.Filter filter;

    public LocalPreference.Filter getFilter() {
       return filter;
    }

    public void setFilter(LocalPreference.Filter filter) {
       this.filter = filter;
    }
}

LocalPreference:

public class LocalPreference {

    public static void saveLocalPreferences(Activity activity, int maxDistance, int minAge,
                                            int maxAge, boolean showMale, boolean showFemale) {

        Filter filter = new Filter();
        filter.setMaxDistance(maxDistance);
        filter.setMinAge(minAge);
        filter.setMaxAge(maxAge);
        filter.setShowMale(showMale);
        filter.setShowFemale(showFemale);

        BabysitApplication babysitApplication = (BabysitApplication) activity.getApplication();
        babysitApplication.setFilter(filter);

        SecurePreferences securePreferences = new SecurePreferences(activity.getApplicationContext());
        securePreferences.edit().putInt(Preference.FILER_MAX_DISTANCE.toString(), maxDistance).apply();
        securePreferences.edit().putInt(Preference.FILER_MIN_AGE.toString(), minAge).apply();
        securePreferences.edit().putInt(Preference.FILER_MAX_AGE.toString(), maxAge).apply();
        securePreferences.edit().putBoolean(Preference.FILER_SHOW_MALE.toString(), showMale).apply();
        securePreferences.edit().putBoolean(Preference.FILER_SHOW_FEMALE.toString(), showFemale).apply();
    }

    public static Filter getLocalPreferences(Activity activity) {

        BabysitApplication babysitApplication = (BabysitApplication) activity.getApplication();
        Filter applicationFilter = babysitApplication.getFilter();

        if (applicationFilter != null) {
            return applicationFilter;
        } else {
            Filter filter = new Filter();
            SecurePreferences securePreferences = new SecurePreferences(activity.getApplicationContext());
            filter.setMaxDistance(securePreferences.getInt(Preference.FILER_MAX_DISTANCE.toString(), 20));
            filter.setMinAge(securePreferences.getInt(Preference.FILER_MIN_AGE.toString(), 15));
            filter.setMaxAge(securePreferences.getInt(Preference.FILER_MAX_AGE.toString(), 50));
            filter.setShowMale(securePreferences.getBoolean(Preference.FILER_SHOW_MALE.toString(), true));
            filter.setShowFemale(securePreferences.getBoolean(Preference.FILER_SHOW_FEMALE.toString(), true));
            babysitApplication.setFilter(filter);
            return filter;
        }
    }

    public static class Filter {
        private int maxDistance;
        private int minAge;
        private int maxAge;
        private boolean showMale;
        private boolean showFemale;

        public int getMaxDistance() {
            return maxDistance;
        }

        public void setMaxDistance(int maxDistance) {
            this.maxDistance = maxDistance;
        }

        public int getMinAge() {
            return minAge;
        }

        public void setMinAge(int minAge) {
            this.minAge = minAge;
        }

        public int getMaxAge() {
            return maxAge;
        }

        public void setMaxAge(int maxAge) {
            this.maxAge = maxAge;
        }

        public boolean isShowMale() {
            return showMale;
        }

        public void setShowMale(boolean showMale) {
            this.showMale = showMale;
        }

        public boolean isShowFemale() {
            return showFemale;
        }

        public void setShowFemale(boolean showFemale) {
            this.showFemale = showFemale;
        }
    }

}

MainActivity (गतिविधि जो आपके आवेदन में पहले कहा जाता है):

LocalPreference.getLocalPreferences(this);

समझाया गया कदम:

  1. मुख्य गतिविधि कॉल getLocalPreferences (यह) -> यह आपकी प्राथमिकताओं को पढ़ेगा, आपके एप्लिकेशन क्लास में फ़िल्टर ऑब्जेक्ट सेट करेगा और इसे लौटाएगा।
  2. जब आप getLocalPreferences () फ़ंक्शन को कहीं और फिर से एप्लिकेशन में कॉल करते हैं तो यह पहली बार जांचता है कि क्या यह एप्लिकेशन क्लास में उपलब्ध नहीं है जो बहुत तेज है।

नोट: हमेशा की जाँच करें अगर एक आवेदन व्यापक चर NULL, कारण से अलग है -> http://www.developerphil.com/dont-store-data-in-the-application-object/

एप्लिकेशन ऑब्जेक्ट हमेशा के लिए स्मृति में नहीं रहेगा, यह मारा जाएगा। आम धारणा के विपरीत, ऐप को स्क्रैच से रीस्टार्ट नहीं किया जाएगा। एंड्रॉइड एक नया एप्लिकेशन ऑब्जेक्ट बनाएगा और उस गतिविधि को शुरू करेगा जहां उपयोगकर्ता यह भ्रम देने से पहले था कि एप्लिकेशन को पहले स्थान पर कभी नहीं मारा गया था।

अगर मैं अशक्त पर जाँच नहीं करता था, तो मैं एक नलपॉंटर को फेंकने की अनुमति दूंगा जब उदाहरण के लिए कॉल करते समय getMaxDistance () फ़िल्टर ऑब्जेक्ट पर (यदि एप्लिकेशन ऑब्जेक्ट एंड्रॉइड द्वारा मेमोरी से स्वाइप किया गया था)


0

SharedPreferences वर्ग डिस्क पर XML फ़ाइलों के भीतर कुछ पढ़ता है और लिखता है, इसलिए किसी भी अन्य IO ऑपरेशन की तरह यह अवरुद्ध हो सकता है। वर्तमान में SharedPreferences में संग्रहीत डेटा की मात्रा API कॉल द्वारा उपभोग किए गए समय और संसाधन को प्रभावित करती है। डेटा की न्यूनतम मात्रा के लिए यह डेटा प्राप्त करने / लगाने के लिए कुछ मिलीसेकंड (कभी-कभी एक मिलीसेकंड से भी कम) की बात है। लेकिन एक विशेषज्ञ के दृष्टिकोण से पृष्ठभूमि में एपीआई कॉल करके प्रदर्शन में सुधार करना महत्वपूर्ण हो सकता है। एक अतुल्यकालिक शेयर्डप्रिफरेंस के लिए मैं डेटम लाइब्रेरी की जाँच करने का सुझाव देता हूँ ।

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