Должен ли доступ к SharedPreferences делать из streamа пользовательского интерфейса?

С выпуском Gingerbread я экспериментировал с некоторыми из новых API, одним из которых является StrictMode .

Я заметил, что одно из предупреждений – для getSharedPreferences() .

Это предупреждение:

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

и он предоставляется для getSharedPreferences() , выполняемого в streamе пользовательского интерфейса.

Должен SharedPreferences доступ к SharedPreferences и изменения действительно выполняться из streamа пользовательского интерфейса?

    Я рад, что вы уже играете с этим!

    Некоторые вещи, которые следует отметить: (в ленивой форме пули)

    • если это худшее из ваших проблем, ваше приложение, вероятно, находится в хорошем месте. 🙂 Записи, как правило, медленнее, чем чтение, поэтому убедитесь, что вы используете SharedPreferenced $ Editor.apply () вместо commit (). apply () является новым в GB и асинхронным (но всегда безопасным, тщательным переходом на жизненный цикл). Вы можете использовать reflection для условного вызова apply () на GB + и commit () на Froyo или ниже. Я буду делать blogpost с образцом кода, как это сделать.

    Что касается загрузки, хотя …

    • Когда-то загруженные, SharedPreferences являются одноточечными и кэшируются по всему процессу. поэтому вы хотите загрузить его как можно раньше, чтобы иметь его в памяти, прежде чем он вам понадобится. (предполагая, что он мал, как и должно быть, если вы используете SharedPreferences, простой XML-файл …). Вы не хотите, чтобы это произошло в будущем, некоторые пользователи нажимают кнопку.

    • но всякий раз, когда вы вызываете context.getSharedPreferences (…), файл базы данных поддержки находится в состоянии stat’d, чтобы увидеть, изменилось ли оно, поэтому вы хотите избежать такой статистики во время событий пользовательского интерфейса. Стат обычно должен быть быстрым (и часто кэшированным), но у yaffs не так много на пути параллелизма (и многие Android-устройства работают на yaffs … Droid, Nexus One и т. Д.), Поэтому, если вы избежите диска , вы избегаете застревания за другими в полете или в ожидании операций на диске.

    • поэтому вы, вероятно, захотите загрузить SharedPreferences во время onCreate () и повторно использовать один и тот же экземпляр, избегая stat.

    • но если вам не нужны ваши предпочтения в любом случае во время onCreate (), это время загрузки застопоривает запуск вашего приложения без необходимости, поэтому обычно лучше иметь что-то вроде подclassа FutureTask , который запускает новый stream в .set () значение подclassа FutureTask. Затем просто найдите свой член FutureTask , когда вам это нужно, и .get (). Я планирую сделать это бесплатно за кадром в Honeycomb, прозрачно. Я попытаюсь выпустить пример кода, который показывает лучшие практики в этой области.

    Просмотрите блог разработчиков Android для предстоящих сообщений по темам, связанным с StrictMode, на следующей неделе.

    Доступ к общим настройкам может занять довольно много времени, поскольку они считываются из флэш-памяти. Вы много читаете? Возможно, вы могли бы использовать другой формат, например, базу данных SQLite.

    Но не исправить все, что вы найдете, используя StrictMode. Или процитировать документацию:

    Но не чувствуйте себя обязанным исправить все, что обнаружил StrictMode. В частности, во время обычного жизненного цикла активности часто требуется много случаев доступа к диску. Используйте StrictMode, чтобы найти то, что вы делали случайно. Однако сетевые запросы в streamе пользовательского интерфейса почти всегда являются проблемой.

    Одна тонкость в ответе Брэда: даже если вы загружаете SharedPreferences в onCreate (), вы, вероятно, должны читать значения в фоновом streamе, потому что getString () и т. Д. Блокируют до чтения предпочтений разделяемых файлов в финишах (в фоновом streamе):

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

    edit () также блокирует то же самое, хотя apply () кажется безопасным в streamе переднего плана.

    (BTW извините, что поставил это здесь. Я бы поставил это в качестве комментария к ответу Брэда, но я просто присоединился и не имел достаточной репутации, чтобы сделать это.)

    Я знаю, что это старый вопрос, но я хочу поделиться своим подходом. У меня было много времени на чтение и использовалось сочетание общих предпочтений и глобального classа приложений:

    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 (this) ->, это будет читать ваши настройки, установить объект фильтра в вашем classе приложения и вернуть его.
    2. Когда вы снова вызываете функцию getLocalPreferences () где-то еще в приложении, она сначала проверяет, не является ли это в classе приложения намного быстрее.

    ПРИМЕЧАНИЕ. ВСЕГДА проверяйте, отличается ли переменная приложения от NULL, причина -> http://www.developerphil.com/dont-store-data-in-the-application-object/

    Объект приложения не останется в памяти навсегда, он будет убит. Вопреки распространенному мнению, приложение не будет перезапущено с нуля. Android создаст новый объект приложения и начнет действие, в котором пользователь раньше был, чтобы представить иллюзию, что приложение никогда не было убито в первую очередь.

    Если бы я не проверял значение null, я бы разрешил выброс nullpointer при вызове, например, getMaxDistance () объекта фильтра (если объект приложения был выведен из памяти Android)

    Interesting Posts
    Давайте будем гением компьютера.