android - Use SharedPreferences en modo multiproceso
service multiprocessing (7)
recuerda que el uso de objetos de contexto como campo estático, tiene el riesgo de fuga de contexto porque no declara el objeto en la clase de aplicación
public class CustomApplication extends Application{
private Prefs prefs;
public void onCreate(){
prefs = new Prefs(this);
}
public Prefs getPrefs(){
return prefs;
}
}
Desde cualquier contexto, puedes obtener los prefs
((MyApplication)context.getApplicationContext()).getPrefs();
SharedPreferences
una instancia de SharedPreferences
que se usaba en el modo multiproceso.
public class Prefs {
private static SharedPreferences prefs;
private static SharedPreferences.Editor editor;
private static void init(Context context) {
prefs = context.getSharedPreferences("alaki",
Context.MODE_MULTI_PROCESS);
editor = prefs.edit();
}
// static methods to set and get preferences
}
Ahora estoy usando esta clase en un servicio con proceso separado y también en mi proceso principal de aplicación de manera estática.
Todo va bien, pero a veces se eliminan todos los datos almacenados en la instancia de SharedPreferences.
¿Como puedó resolver esté problema?
Editar: Finalmente resolví mi problema usando IPC.
Si dos procesos escriben datos en SharedPreferences, es posible que todas las SharedPreferences se restablezcan a los valores predeterminados.
También puedes intentar llamar a clear()
en el editor antes de guardar val
SharedPreferences.Editor sp = settings.edit();
sp.clear();
sp.putString("Name", "YourName");
sp.commit();
SharedPreferences en sí no es seguro para el proceso. Esa es probablemente la razón por la cual la documentación de SharedPreferences dice
Nota: actualmente esta clase no admite el uso en múltiples procesos. Esto se agregará más tarde.
El uso del método commit()
almacena los cambios en el almacenamiento persistente, por lo tanto, es lento y generaría conflictos entre llamadas múltiples desde otros procesos.
Sin embargo, existe una alternativa a este método, debe llamar al método apply()
, este método almacena los cambios en la memoria y luego en el almacenamiento en disco de forma asíncrona, por lo que es más confiable.
Use un proveedor de contenido que use SharedPreferences. Ejemplo ver aquí: https://github.com/hamsterksu/MultiprocessPreferences
Actualmente no hay forma de acceder de forma segura a SharedPreferences
en múltiples procesos, como se describe en su documentación .
Nota: actualmente esta clase no admite el uso en múltiples procesos. Esto se agregará más tarde.
Después de probar mucho con MODE_MULTI_PROCESS
, tengo tres pruebas para compartir:
1- Inicialice SharedPreferences
una vez en cada proceso y utilícelo varias veces.
El problema: los valores no se reflejan en cada proceso como se esperaba. Por lo tanto, cada proceso tiene su propio valor de SharedPreferences.
2- Inicializar las SharedPreferences
en cada put u get.
Esto realmente funciona y el valor ahora es intercambiable entre procesos.
El problema: a veces, después de acceder de forma agresiva a sharedpref, el archivo de preferencias compartidas se elimina con todo su contenido, como se describe en este número , y aparece esta advertencia en el registro:
W/FileUtils﹕ Failed to chmod(/data/data/com.hegazy.multiprocesssharedpref/shared_prefs/myprefs.xml): android.system.ErrnoException: chmod failed: ENOENT (No such file or directory)
Puedes encontrar por qué sucede esto en el problema.
3- Utilice la sincronización para bloquear los métodos que ponen y obtienen valores en SharedPreferences
.
Esto es completamente incorrecto; la sincronización no funciona en todos los procesos. SharedPreferences
está utilizando la sincronización en su implementación, pero eso solo garantiza la seguridad del hilo, no la seguridad del proceso. Esto se describe muy bien aquí .
He trabajado alrededor de esto combinando:
- Proporcionar a cada proceso acceso mutuamente exclusivo al archivo
SharedPreferences
(como mediante el uso de un mecanismo de bloqueo basado en sockets ) -
SharedPreferences
con el indicadorMODE_MULTI_PROCESS
cada vez que quiera usarlo para eludir el almacenamiento en memoria caché en memoria
Esto parece funcionar bien, pero no ha sido probado exhaustivamente en el mundo real, así que no sé si es perfectamente confiable.
Puedes ver un ejemplo de trabajo que escribí aquí .
Advertencia : parece que MODE_MULTI_PROCESS
ha quedado obsoleto en Android M. Podría dejar de funcionar en el futuro.