2010-12-06 11 views
90

जिंजरब्रेड की रिहाई के साथ, मैं नई एपीआई के कुछ, उन्हें जा रहा है StrictMode में से एक के साथ प्रयोग किया गया है।साझा किए गए संदर्भों को एक्सेस करना यूआई थ्रेड से किया जाना चाहिए?

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

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

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

और यह एक getSharedPreferences() कॉल यूआई धागे पर बनाया जा रहा है के लिए दिया जा रहा है।

चाहिए SharedPreferences का उपयोग और परिवर्तन वास्तव में यूआई धागा बंद कर दिया जा सकता है?

+0

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

उत्तर

157

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

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

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

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

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

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

  • तो शायद आप अपने ऑनक्रेट() के दौरान साझा किए गए संदर्भ लोड करना चाहते हैं और स्टेट से परहेज करते हुए, उसी उदाहरण का पुन: उपयोग करना चाहते हैं।

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

चेक आने वाले सप्ताह (रों) में होने वाली StrictMode से संबंधित विषयों पर आगामी पदों के लिए Android डेवलपर ब्लॉग।

ब्राड के जवाब के बारे में
+0

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

+6

इस अद्भुत पोस्ट के नए पाठकों के लाभ के लिए, ऊपर दिए गए ब्लॉग पोस्ट के लिंक को नीचे देखें, @ ब्रैड फिट्जपैट्रिक द्वारा: [एंड्रॉइड डेवलपर का ब्लॉग पोस्ट ब्रैड द्वारा सख्त मोड पर] [http://android-developers.blogspot.de /2010/12/new-gingerbread-api-strictmode.html)। इस पोस्ट में साझा संदर्भों को संग्रहीत करने के लिए एंड्रॉइड संस्करण के आधार पर लागू (जिंजरब्रेड आगे से) या प्रतिबद्ध (फ्रोयो) का उपयोग करने के लिए नमूना कोड का एक लिंक भी है: [सशर्त रूप से लागू या प्रतिबद्ध करें] (https://code.google.com/p /zippy-android/source/browse/trunk/examples/SharedPreferencesCompat.java) –

+4

क्या यह अभी भी आईसीएस \ जेबी पर प्रासंगिक है? – ekatz

5

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

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

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

+5

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

+0

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

3

एक सूक्ष्मता: भले ही आप OnCreate() में SharedPreferences लोड करते हैं, तो आप शायद अभी भी मूल्यों पृष्ठभूमि धागे पर क्योंकि GetString() आदि ब्लॉक पृष्ठभूमि पर खत्म में साझा फ़ाइल वरीयता (पढ़ने जब तक पढ़ना चाहिए धागा):

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

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

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

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

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

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

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

संबंधित मुद्दे