¿Debería acceder a las Preferencias Compartidas desde el subproceso UI?

Con el lanzamiento de Gingerbread, he estado experimentando con algunas de las nuevas API, una de ellas es StrictMode .

Noté que una de las advertencias es para getSharedPreferences() .

Esta es la advertencia:

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

y se está dando para que se getSharedPreferences() una getSharedPreferences() a getSharedPreferences() en el hilo de la interfaz de usuario.

¿ SharedPreferences acceso y los cambios de SharedPreferences realmente hacerse fuera del hilo de UI?

¡Me alegra que ya juegues con eso!

Algunas cosas a tener en cuenta: (en forma de bala perdida)

  • si este es el peor de tus problemas, tu aplicación probablemente esté en un buen lugar. 🙂 Las escrituras generalmente son más lentas que las lecturas, así que asegúrese de estar utilizando SharedPreferenced $ Editor.apply () en lugar de commit (). apply () es nuevo en GB y async (pero siempre seguro, cuidado con las transiciones del ciclo de vida). Puede usar reflection para llamar condicionalmente a apply () en GB + y commit () en Froyo o abajo. Haré una publicación de blog con código de muestra de cómo hacer esto.

En cuanto a la carga, aunque …

  • una vez cargadas, SharedPreferences son singletons y se almacenan en caché en todo el proceso. por lo que desea cargarlo lo antes posible para que lo tenga en la memoria antes de que lo necesite. (suponiendo que es pequeño, como debería ser si está utilizando SharedPreferences, un archivo XML simple …) No querrá fallar en el futuro si algún usuario hace clic en un botón.

  • pero siempre que llame a context.getSharedPreferences (…), el archivo XML de respaldo está listo para ver si ha cambiado, por lo que querrá evitar esas estadísticas durante los eventos de IU de todos modos. Una estadística normalmente debería ser rápida (y a menudo almacenada en caché), pero yaffs no tiene demasiada concurrencia (y muchos dispositivos Android corren en yaffs … Droid, Nexus One, etc.) así que si evitas el disco , evita evitar atascarse detrás de otras operaciones de disco pendientes o en vuelo.

  • por lo que probablemente desee cargar las Preferencias Compartidas durante su onCreate () y reutilizar la misma instancia, evitando la estadística.

  • pero si no necesita sus preferencias de todos modos durante onCreate (), ese tiempo de carga demora innecesariamente la puesta en marcha de su aplicación, por lo que generalmente es mejor tener algo como una subclase FutureTask que inicie un nuevo hilo para .set () el valor de las subclases FutureTask. Luego solo busque su miembro FutureTask cuando lo necesite y .get (). Planeo hacer esto gratis detrás de escena en Honeycomb, de forma transparente. Trataré de lanzar algún código de muestra que muestre las mejores prácticas en esta área.

Consulte en el blog de Desarrolladores de Android las próximas publicaciones sobre temas relacionados con StrictMode en la (s) próxima (s) semana (s).

El acceso a las preferencias compartidas puede llevar bastante tiempo porque se leen desde el almacenamiento flash. ¿Lees mucho? Tal vez podrías usar un formato diferente, por ejemplo, una base de datos SQLite.

Pero no arregle todo lo que encuentre usando StrictMode. O para citar la documentación:

Pero no se sienta obligado a arreglar todo lo que StrictMode encuentre. En particular, muchos casos de acceso a disco a menudo son necesarios durante el ciclo de vida de la actividad normal. Usa StrictMode para encontrar cosas que hiciste por accidente. Sin embargo, las solicitudes de red en el hilo de la interfaz de usuario casi siempre son un problema.

Una sutilidad sobre la respuesta de Brad: incluso si carga las Preferencias Compartidas en onCreate (), probablemente debería seguir leyendo los valores en la cadena de fondo porque getString () etc. bloquea hasta leer la preferencia de archivos compartidos en los finales (en una cadena de fondo):

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

edit () también bloquea de la misma manera, aunque apply () parece estar seguro en el hilo de primer plano.

(Por cierto, siento dejar esto aquí. Hubiera puesto esto como un comentario en la respuesta de Brad, pero acabo de unirme y no tengo suficiente reputación para hacerlo).

Sé que esta es una vieja pregunta, pero quiero compartir mi enfoque. Tenía largos tiempos de lectura y usaba una combinación de preferencias compartidas y la clase de aplicación global:

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 (actividad que se llama primero en su aplicación):

 LocalPreference.getLocalPreferences(this); 

Pasos explicados:

  1. La actividad principal llama a getLocalPreferences (this) -> esto leerá sus preferencias, configurará el objeto de filtro en su clase de aplicación y lo devolverá.
  2. Cuando vuelve a llamar a la función getLocalPreferences () en otro lugar de la aplicación, primero comprueba si no está disponible en la clase de la aplicación, que es mucho más rápida.

NOTA: SIEMPRE verifique si una variable de aplicación amplia es diferente de NULL, razón -> http://www.developerphil.com/dont-store-data-in-the-application-object/

El objeto de la aplicación no permanecerá en la memoria para siempre, será asesinado. Contrario a la creencia popular, la aplicación no se reiniciará desde cero. Android creará un nuevo objeto Aplicación e iniciará la actividad donde el usuario estaba antes para dar la ilusión de que la aplicación nunca se mató en primer lugar.

Si no verificara el nulo, permitiría que se lanzara un nullpointer al llamar, por ejemplo, getMaxDistance () en el objeto de filtro (si el objeto de la aplicación fue borrado de la memoria por Android)