Guardar paquete con SharedPreferences

He hecho todo lo posible para que todos los datos de mi juego para Android encajen en un paquete savedInstanceState. Hay una gran cantidad de datos en total, incluyendo muchos objetos Parcelable. Esto garantiza que cuando la aplicación se detenga o cambie la orientación, no se pierda ningún dato por la actividad que se está recreando.

Sin embargo, recientemente he descubierto que un paquete savedInstanceState aparentemente NO es apropiado para el almacenamiento a largo plazo. Así que estoy buscando una manera que pueda adaptar mi método de ahorro existente para trabajar como una solución a largo plazo, para que el estado del juego siempre se puede restaurar.

He oído hablar de 2 soluciones hasta ahora:

1) Utilice el paquete savedInstanceState para los cambios de orientación, pero también incorpore SharedPrefs para cuando la aplicación necesita ser cerrada por completo.

Esto parece increíblemente contraproducente, ya que utiliza 2 completamente distintos métodos para hacer básicamente lo mismo. Además, ya que mi conjunto savedInstanceState utiliza objetos Parcelable, tendría que dar a cada uno de esos objetos otro método para permitir que se escriban en SharedPrefs. Esencialmente LOTES de código duplicado y difícil de manejar.

2) Serialice el paquete savedInstanceState y escríbalo directamente en un archivo.

Estoy abierto a esto, pero en realidad no sé cómo hacerlo. Sin embargo, sigo sosteniendo la esperanza de que puede haber una mejor solución, como he oído que la serialización en Android es "cómicamente / inusiblemente lento".

Estaría muy agradecido si alguien pudiera proporcionarme una solución a esto.

Divertido, esta semana, el número 47 de Android Weekly desencadenó esta biblioteca: Android preferencias complejas .

Debe caber para usted.

Ahora he llegado con mi propia solución a este problema, que es un medio semi-automático de guardar Bundles a SharedPreferences. Digo semi-automático porque, aunque guardar el Bundle requiere sólo un método, recuperar los datos de nuevo y convertirlo de nuevo en un Bundle requiere algo de trabajo.

Aquí está el código para guardar el Bundle:

SharedPreferences save = getSharedPreferences(SAVE, MODE_PRIVATE); Editor ed = save.edit(); saveBundle(ed, "", gameState); /** * Manually save a Bundle object to SharedPreferences. * @param ed * @param header * @param gameState */ private void saveBundle(Editor ed, String header, Bundle gameState) { Set<String> keySet = gameState.keySet(); Iterator<String> it = keySet.iterator(); while (it.hasNext()){ key = it.next(); o = gameState.get(key); if (o == null){ ed.remove(header + key); } else if (o instanceof Integer){ ed.putInt(header + key, (Integer) o); } else if (o instanceof Long){ ed.putLong(header + key, (Long) o); } else if (o instanceof Boolean){ ed.putBoolean(header + key, (Boolean) o); } else if (o instanceof CharSequence){ ed.putString(header + key, ((CharSequence) o).toString()); } else if (o instanceof Bundle){ saveBundle(header + key, ((Bundle) o)); } } ed.commit(); } 

Tenga en cuenta que sólo he escrito casos para los tipos que necesitaba, pero esto debería ser fácilmente adaptable si tiene paquetes que también incluyen otros tipos.

Este método ahorrará recursivamente otros objetos de Bundle almacenados dentro del Bundle dado. Sin embargo, no funcionará para los objetos Parcelable, así que tuve que alterar mis objetos Parcelable para hacer que ellos mismos se almacenaran en un Bundle. Puesto que los paquetes y los paquetes son bastante similares, esto no era demasiado duro. Creo que los paquetes también pueden ser un poco más lentos que los paquetes, por desgracia.

A continuación, escribí constructores en todos mis objetos previamente Parcelable para permitirles re-Bundle de los datos almacenados SharedPreferences. Es bastante fácil reconstruir las claves de los datos que necesita. Digamos que tiene la siguiente estructura de datos:

 Bundle b { KEY_X -> int x; KEY_Y -> Bundle y { KEY_Z -> int z; } } 

Éstos se guardarán en SharedPreferences de la siguiente manera:

 KEY_X -> x KEY_YKEY_Z -> z 

Puede que no sea el método más bonito del mundo, pero funciona, y me cuesta mucho menos código que la alternativa, ya que ahora mi método onSaveInstanceState y mis métodos onPause usan la misma técnica.

Extendí la respuesta de Dan con una función para recrear los Bundles automáticamente, e hizo que los nombres fueran menos propensos a chocar.

 private static final String SAVED_PREFS_BUNDLE_KEY_SEPARATOR = "§§"; /** * Save a Bundle object to SharedPreferences. * * NOTE: The editor must be writable, and this function does not commit. * * @param editor SharedPreferences Editor * @param key SharedPreferences key under which to store the bundle data. Note this key must * not contain '§§' as it's used as a delimiter * @param preferences Bundled preferences */ public static void savePreferencesBundle(SharedPreferences.Editor editor, String key, Bundle preferences) { Set<String> keySet = preferences.keySet(); Iterator<String> it = keySet.iterator(); String prefKeyPrefix = key + SAVED_PREFS_BUNDLE_KEY_SEPARATOR; while (it.hasNext()){ String bundleKey = it.next(); Object o = preferences.get(bundleKey); if (o == null){ editor.remove(prefKeyPrefix + bundleKey); } else if (o instanceof Integer){ editor.putInt(prefKeyPrefix + bundleKey, (Integer) o); } else if (o instanceof Long){ editor.putLong(prefKeyPrefix + bundleKey, (Long) o); } else if (o instanceof Boolean){ editor.putBoolean(prefKeyPrefix + bundleKey, (Boolean) o); } else if (o instanceof CharSequence){ editor.putString(prefKeyPrefix + bundleKey, ((CharSequence) o).toString()); } else if (o instanceof Bundle){ savePreferencesBundle(editor, prefKeyPrefix + bundleKey, ((Bundle) o)); } } } /** * Load a Bundle object from SharedPreferences. * (that was previously stored using savePreferencesBundle()) * * NOTE: The editor must be writable, and this function does not commit. * * @param sharedPreferences SharedPreferences * @param key SharedPreferences key under which to store the bundle data. Note this key must * not contain '§§' as it's used as a delimiter * * @return bundle loaded from SharedPreferences */ public static Bundle loadPreferencesBundle(SharedPreferences sharedPreferences, String key) { Bundle bundle = new Bundle(); Map<String, ?> all = sharedPreferences.getAll(); Iterator<String> it = all.keySet().iterator(); String prefKeyPrefix = key + SAVED_PREFS_BUNDLE_KEY_SEPARATOR; Set<String> subBundleKeys = new HashSet<String>(); while (it.hasNext()) { String prefKey = it.next(); if (prefKey.startsWith(prefKeyPrefix)) { String bundleKey = StringUtils.removeStart(prefKey, prefKeyPrefix); if (!bundleKey.contains(SAVED_PREFS_BUNDLE_KEY_SEPARATOR)) { Object o = all.get(prefKey); if (o == null) { // Ignore null keys } else if (o instanceof Integer) { bundle.putInt(bundleKey, (Integer) o); } else if (o instanceof Long) { bundle.putLong(bundleKey, (Long) o); } else if (o instanceof Boolean) { bundle.putBoolean(bundleKey, (Boolean) o); } else if (o instanceof CharSequence) { bundle.putString(bundleKey, ((CharSequence) o).toString()); } } else { // Key is for a sub bundle String subBundleKey = StringUtils.substringBefore(bundleKey, SAVED_PREFS_BUNDLE_KEY_SEPARATOR); subBundleKeys.add(subBundleKey); } } else { // Key is not related to this bundle. } } // Recursively process the sub-bundles for (String subBundleKey : subBundleKeys) { Bundle subBundle = loadPreferencesBundle(sharedPreferences, prefKeyPrefix + subBundleKey); bundle.putBundle(subBundleKey, subBundle); } return bundle; } 
  • Cifrar datos en SharedPreferences
  • Android SharedPreferences después de reiniciar el dispositivo
  • Cómo Android SharedPreferences guarda / almacena un objeto
  • Android - sharedferences devuelve valor nulo
  • Mantener más de un archivo de preferencias compartidas en android
  • ¿Cómo usar las Preferencias Compartidas en MVP sin Dagger y no hacer que Presenter dependa del contexto?
  • SharedPreferences Valor largo
  • Android se niega a escribir / crear archivos de preferencias compartidas
  • Android SharedPreferences, cómo guardar una variable int simple
  • Convertir ArrayList con Gson a String
  • ¿Pueden las preferencias compartidas ser privadas?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.