¿Cuál es la diferencia entre commit () y apply () en SharedPreferences

431

Estoy usando SharedPreferencesen mi aplicación de Android. Estoy usando ambos commit()y el apply()método de preferencia compartida. Cuando uso AVD 2.3 no muestra ningún error, pero cuando ejecuto el código en AVD 2.1, el apply()método muestra un error.

Entonces, ¿cuál es la diferencia entre estos dos? ¿Y usando solo commit()puedo almacenar el valor de preferencia sin ningún problema?

Andro Selva
fuente
115
Esto tiene un año, pero voy a comentarlo de todos modos, aunque puede ser obvio, ninguna de las respuestas hace este punto: apply()hará asincrónicamente las E / S de disco mientras commit()esté sincronizado. Entonces realmente no deberías llamar commit()desde el hilo de la interfaz de usuario.
michiakig
Es de destacar que cuando se utilizan múltiples objetos SharedPreferences.Editor, apply()gana el último llamado . Por lo tanto, puede usarlo apply()en lugar de commit()forma segura si se asegura de que solo su aplicación esté utilizando un SharedPreferences.Editor.
aoeu
2
Según la advertencia de Android Studio Lint: commit () guardará los datos de forma inmediata y sincrónica. Sin embargo, apply () lo guardará de forma asincrónica (en segundo plano) y, por lo tanto, mejorará el rendimiento. Es por eso que se prefiere apply () sobre commit () si no le importa su tipo de retorno (si los datos se guardan correctamente o no).
Rahul Raina
¿Hay alguna forma de desactivar la advertencia de pelusa cuando se usa commit()?
QED

Respuestas:

653

apply()se agregó en 2.3, se compromete sin devolver un valor booleano que indica éxito o falla.

commit()devuelve verdadero si el guardado funciona, falso de lo contrario.

apply() se agregó cuando el equipo de desarrollo de Android notó que casi nadie se dio cuenta del valor de retorno, por lo que aplicar es más rápido ya que es asíncrono.

http://developer.android.com/reference/android/content/SharedPreferences.Editor.html#apply ()

Ray Britton
fuente
8
Esta respuesta es cierta, pero supongo que el comentario de @spacemanaki anterior también es cierto, contiene información valiosa
Aksel Fatih
58
commit () escribe sus datos en el almacenamiento persistente de inmediato, mientras que apply () lo manejará en segundo plano.
capt.swag
18
¿crea una condición de carrera?
ChrisMcJava
42
¿Qué sucede si escribo algo con apply () e intento leerlo inmediatamente después? ¿Se garantiza que la lectura me dará el valor más nuevo? Los documentos dicen que si se produce otro commit () después de que se aplica apply (), ese commit () se bloqueará hasta que el apply () persista en el disco, lo que deja en claro que este problema no ocurre cuando se trata de operaciones de 'escritura' , pero ¿qué pasa si estás escribiendo y leyendo inmediatamente después? De mis pruebas, se devuelve el valor más nuevo, pero quiero saber si está 100% garantizado o no.
Tiago
22
es seguro reemplazar cualquier instancia de commit () con apply () ver developer.android.com/reference/android/content/…
Tigran Sarkisian
221

tl; dr:

  • commit()escribe los datos sincrónicamente (bloqueando el hilo desde el que se llama). Luego le informa sobre el éxito de la operación.
  • apply()programa los datos para que se escriban de forma asincrónica . No le informa sobre el éxito de la operación.
  • Si guarda con apply()e inmediatamente lee a través de cualquier método getX, ¡se devolverá el nuevo valor!
  • Si llamó apply()en algún momento y todavía se está ejecutando, cualquier llamada a commit()se bloqueará hasta que todas las llamadas aplicadas pasadas y la llamada de confirmación actual hayan finalizado.

Más información detallada de SharedPreferences. Documentación del editor :

A diferencia de commit (), que escribe sus preferencias en el almacenamiento persistente de forma síncrona , apply () confirma sus cambios en SharedPreferences en la memoria de forma inmediata, pero inicia una confirmación asíncrona en el disco y no se le notificará ninguna falla . Si otro editor en este SharedPreferences realiza un commit regular () mientras un apply () aún está pendiente, el commit () se bloqueará hasta que se completen todos los commits asíncronos, así como el commit en sí.

Como las instancias SharedPreferences son singletons dentro de un proceso, es seguro reemplazar cualquier instancia de commit () con apply () si ya estaba ignorando el valor de retorno.

No se espera que la interfaz SharedPreferences.Editor se implemente directamente. Sin embargo, si anteriormente lo implementó y ahora está recibiendo errores sobre la falta de apply (), simplemente puede llamar a commit () desde apply ().

Lukas Knuth
fuente
19
Esta es una respuesta mucho mejor ya que menciona que apply()es asíncrona y que las escrituras pendientes bloquean las llamadas futuras commit().
spaaarky21
22

Estoy experimentando algunos problemas al usar apply () en lugar de commit (). Como se indicó anteriormente en otras respuestas, el apply () es asíncrono. Tengo el problema de que los cambios formados en una preferencia de "conjunto de cadenas" nunca se escriben en la memoria persistente.

Ocurre si "fuerza la detención" del programa o, en la ROM que he instalado en mi dispositivo con Android 4.1, cuando el sistema elimina el proceso debido a necesidades de memoria.

Recomiendo usar "commit ()" en lugar de "apply ()" si quieres que tus preferencias estén activas.

JoseLSegura
fuente
¿Estás seguro de que tu problema no está relacionado debido al subproceso concurrente? Después de enviar apply (), debe esperar un momento para leer las cosas que agregó; de lo contrario, el subproceso de la interfaz de usuario intentará leer antes de que el subproceso de trabajo de apply () confirme los cambios.
Marco Altran
Con respecto al conjunto de cadenas, stackoverflow.com/questions/16820252/…
Tapirboy
@JoseLSegura: los documentos sugieren lo contrario: developer.android.com/intl/ja/reference/android/content/… "No necesita preocuparse por los ciclos de vida de los componentes de Android y su interacción con la escritura de apply () en el disco. El marco se asegura de que las escrituras en disco en vuelo desde apply () se completen antes de cambiar de estado ". Me pregunto si lo que está viendo es un error en Android y, de ser así, si se ha solucionado en versiones más recientes.
ToolmakerSteve
El mismo problema me estaba ocurriendo usando la biblioteca "ProcessPhoenix" para restablecer mi aplicación. Estaba guardando una preferencia justo antes de realizar un reinicio, y "aplicar" no funcionaba.
ElYeante
14

Utilice apply ().

Escribe los cambios en la RAM de inmediato y espera y lo escribe en el almacenamiento interno (el archivo de preferencias real) después. Commit escribe los cambios sincrónicamente y directamente en el archivo.

Mustafa
fuente
14
  • commit()es sincrónico, apply()es asincrónico

  • apply() Es una función nula.

  • commit() devuelve verdadero si los nuevos valores se escribieron correctamente en el almacenamiento persistente.

  • apply() garantías completas antes de cambiar de estado, no necesita preocuparse por los ciclos de vida de los componentes de Android

Si no usa el valor devuelto por commit()y está usando el commit()hilo principal, use en apply()lugar de commit()

Nurlan Sofiyev
fuente
13

Los documentos dan una muy buena explicación de la diferencia entre apply()y commit():

A diferencia commit(), que escribe sus preferencias en el almacenamiento persistente de forma síncrona, apply()confirma sus cambios en la memoria de SharedPreferencesinmediato, pero inicia una confirmación asíncrona en el disco y no se le notificará ninguna falla. Si otro editor en esto SharedPreferenceshace un regular commit()mientras apply()todavía está pendiente, commit()se bloqueará hasta que se completen todas las confirmaciones asíncronas, así como la confirmación misma. Como SharedPreferenceslos casos son únicos dentro de un proceso, que es seguro para reemplazar cualquier instancia de commit()con apply()si ya no tenían en cuenta el valor de retorno.

Mojo Risin
fuente
6

De javadoc:

A diferencia de commit (), que escribe sus preferencias en el almacenamiento persistente de forma síncrona, apply () confirma sus cambios en SharedPreferences en la memoria de forma inmediata, pero inicia una confirmación asíncrona en el disco y no se le notificará ninguna falla. Si otro editor en este SharedPreferences realiza un commit regular () mientras que> apply () aún está pendiente, el commit () se bloqueará hasta que se completen todos los commits asíncronos, así como el commit en sí

Vladimir Ivanov
fuente
1

La diferencia entre commit () y apply ()

Podríamos estar confundidos por esos dos términos, cuando estamos usando SharedPreference. Básicamente son probablemente los mismos, así que aclaremos las diferencias de commit () y apply ().

1. Valor de retorno:

apply()se compromete sin devolver un valor booleano que indica éxito o fracaso. commit() devuelve verdadero si el guardado funciona, falso de lo contrario.

  1. Velocidad:

apply()es más rápido. commit()es mas lento

  1. Asíncrono vs Sincrónico:

apply(): Asíncrono commit(): Sincrónico

  1. Atómico:

apply(): atómico commit(): atómico

  1. Notificación de error:

apply(): No commit(): Sí

Chanaka Weerasinghe
fuente
¿Cómo es apply()"más rápido" que commit()? Básicamente representan una misma tarea que se colocaría en Looper del hilo. commit()coloca esa tarea en el bucle principal mientras la apply()toma en segundo plano, manteniendo así al bucle principal libre de tareas de E / S de disco.
Taseer
A diferencia de commit (), que escribe sus preferencias en el almacenamiento persistente de forma síncrona, apply () confirma sus cambios en SharedPreferences en la memoria de forma inmediata, pero inicia una confirmación asíncrona en el disco y no se le notificará ninguna falla. Si otro editor en este SharedPreferences realiza un commit regular () mientras un apply () aún está pendiente, el commit () se bloqueará hasta que se completen todos los commits asíncronos, así como el commit en sí mismo, consulte el desarrollador
Chanaka Weerasinghe