Quelle est la différence entre commit () et apply () dans SharedPreferences

431

J'utilise SharedPreferencesdans mon application Android. J'utilise les deux commit()et la apply()méthode de préférence partagée. Lorsque j'utilise AVD 2.3, il ne montre aucune erreur, mais lorsque j'exécute le code dans AVD 2.1, la apply()méthode affiche une erreur.

Alors, quelle est la différence entre ces deux? Et en utilisant uniquement, commit()puis-je stocker la valeur de préférence sans aucun problème?

Andro Selva
la source
115
Cela fait un an, mais je vais quand même le commenter, bien que cela puisse être évident, aucune des réponses ne fait le point: apply()fera les E / S disque de manière asynchrone alors qu'il commit()est synchrone. Donc, vous ne devriez vraiment pas appeler à commit()partir du thread d'interface utilisateur.
michiakig
Il convient de noter que lorsque plusieurs objets SharedPreferences.Editor sont utilisés, le dernier à appeler apply()gagne. Par conséquent, vous pouvez utiliser apply()en lieu et place en commit()toute sécurité si vous vous assurez qu'un seul SharedPreferences.Editor est utilisé par votre application.
aoeu
2
Conformément à l'avertissement Android Studio Lint: commit () enregistre les données immédiatement et de manière synchrone. Cependant, apply () l'enregistrera de manière asynchrone (en arrière-plan) et améliorera ainsi certaines performances. C'est pourquoi apply () est préférable à commit () si vous ne vous souciez pas de son type de retour (si les données sont enregistrées avec succès ou non).
Rahul Raina
Existe-t-il un moyen de désactiver l'avertissement Lint lors de l'utilisation commit()?
QED

Réponses:

653

apply()a été ajouté en 2.3, il valide sans retourner un booléen indiquant un succès ou un échec.

commit()renvoie vrai si la sauvegarde fonctionne, faux sinon.

apply() a été ajouté car l'équipe de développement Android a remarqué que presque personne n'avait remarqué la valeur de retour, donc appliquer est plus rapide car il est asynchrone.

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

Ray Britton
la source
8
Cette réponse est vraie, mais je suppose que le commentaire de @spacemanaki ci-dessus est également vrai contient des informations précieuses
Aksel Fatih
58
commit () écrit ses données dans un stockage persistant immédiatement, alors que apply () les gère en arrière-plan.
capt.swag
18
crée-t-il une condition de concurrence?
ChrisMcJava
42
Que se passe-t-il si j'écris quelque chose avec apply () et que j'essaye de le lire immédiatement après? La lecture est-elle garantie de me donner la valeur la plus récente? Les documents indiquent que si un autre commit () se produit après le déclenchement de apply (), ce commit () se bloquera jusqu'à ce que apply () soit conservé sur le disque, ce qui indique clairement que ce problème ne se produit pas lorsqu'il s'agit d'opérations d'écriture. , mais qu'en est-il si vous écrivez et lisez immédiatement après? D'après mes tests, la valeur la plus récente est renvoyée, mais je veux savoir si elle est garantie à 100% ou non.
Tiago
22
il est sûr de remplacer n'importe quelle instance de commit () par apply () voir developer.android.com/reference/android/content/…
Tigran Sarkisian
221

tl; dr:

  • commit()écrit les données de façon synchrone (bloquant le thread appelé). Il vous informe ensuite du succès de l'opération.
  • apply()planifie l'écriture asynchrone des données . Il ne vous informe pas du succès de l'opération.
  • Si vous enregistrez avec apply()et lisez immédiatement via n'importe quelle méthode getX, la nouvelle valeur sera retournée!
  • Si vous avez appelé apply()à un moment donné et qu'il est toujours en cours d'exécution, tous les appels à commit()seront bloqués jusqu'à ce que tous les appels d'application passés et l'appel de validation en cours soient terminés.

Informations plus détaillées dans la documentation SharedPreferences.Editor :

Contrairement à commit (), qui écrit ses préférences sur le stockage persistant de manière synchrone , apply () valide immédiatement ses modifications dans les SharedPreferences en mémoire, mais démarre une validation asynchrone sur le disque et vous ne serez pas informé des échecs . Si un autre éditeur de ce SharedPreferences effectue un commit () normal alors qu'un apply () est toujours en attente, le commit () se bloquera jusqu'à ce que tous les commit asynchrones soient terminés ainsi que le commit lui-même.

Comme les instances SharedPreferences sont des singletons dans un processus, il est prudent de remplacer toute instance de commit () par apply () si vous ignoriez déjà la valeur de retour.

L'interface SharedPreferences.Editor ne devrait pas être implémentée directement. Cependant, si vous l'avez déjà implémenté et que vous obtenez maintenant des erreurs concernant le manquant apply (), vous pouvez simplement appeler commit () depuis apply ().

Lukas Knuth
la source
19
C'est une bien meilleure réponse car elle mentionne que apply()les écritures asynchrones et en attente bloquent les appels futurs vers commit().
spaaarky21
22

Je rencontre des problèmes avec apply () à la place commit (). Comme indiqué précédemment dans d'autres réponses, la méthode apply () est asynchrone. J'obtiens le problème que les modifications apportées à une préférence "jeu de chaînes" ne sont jamais écrites dans la mémoire persistante.

Cela se produit si vous "forcez la détention" du programme ou, dans la ROM que j'ai installée sur mon appareil avec Android 4.1, lorsque le processus est tué par le système en raison de besoins en mémoire.

Je recommande d'utiliser "commit ()" à la place de "apply ()" si vous voulez que vos préférences soient vivantes.

JoseLSegura
la source
Êtes-vous sûr que votre problème n'est pas lié à un filetage simultané? Après avoir envoyé apply (), vous devez attendre un moment pour lire les éléments que vous avez ajoutés, sinon le thread d'interface utilisateur tentera de lire avant que le thread de travail de apply () n'engage les modifications.
Marco Altran
En ce qui concerne le jeu de cordes, stackoverflow.com/questions/16820252/…
Tapirboy
@JoseLSegura - les documents suggèrent le contraire: developer.android.com/intl/ja/reference/android/content/… "Vous n'avez pas à vous soucier des cycles de vie des composants Android et de leur interaction avec l'écriture apply () sur le disque. s'assure que le disque en vol écrit à partir de apply () avant de changer d'état. " Je me demande si ce que vous voyez est un bogue dans Android, et si oui, s'il a été corrigé dans les versions plus récentes.
ToolmakerSteve
Le même problème m'arrivait en utilisant la bibliothèque "ProcessPhoenix" pour réinitialiser mon application. J'enregistrais une préférence juste avant d'effectuer une réinitialisation et «appliquer» ne fonctionnait pas.
ElYeante
14

Utilisez Appliquer ().

Il écrit les modifications dans la RAM immédiatement et attend et les écrit dans la mémoire interne (le fichier de préférence réel) après. Commit écrit les modifications de manière synchrone et directe dans le fichier.

Mustafa
la source
14
  • commit()est synchrone, apply()est asynchrone

  • apply() est une fonction nulle.

  • commit() renvoie true si les nouvelles valeurs ont été correctement écrites sur le stockage persistant.

  • apply() garanties complètes avant de changer d'état, vous n'avez pas à vous soucier des cycles de vie des composants Android

Si vous n'utilisez pas la valeur renvoyée par commit()et que vous utilisez à commit()partir du thread principal, utilisez apply()au lieu de commit()

Nurlan Sofiyev
la source
13

Les documents donnent une assez bonne explication de la différence entre apply()et commit():

Contrairement à commit(), qui écrit ses préférences sur le stockage persistant de manière synchrone, apply()valide SharedPreferencesimmédiatement ses modifications dans la mémoire mais démarre une validation asynchrone sur le disque et vous ne serez pas informé des échecs. Si un autre éditeur à ce sujet SharedPreferenceseffectue une opération régulière commit()alors que a apply()est toujours en attente, le commit()bloc se bloquera jusqu'à ce que toutes les validations asynchrones soient terminées ainsi que la validation elle-même. Comme les SharedPreferencesinstances sont des singletons dans un processus, il est sûr de remplacer n'importe quelle instance de commit()avec apply()si vous ignoriez déjà la valeur de retour.

Mojo Risin
la source
6

De javadoc:

Contrairement à commit (), qui écrit ses préférences sur le stockage persistant de manière synchrone, apply () valide immédiatement ses modifications dans les SharedPreferences en mémoire, mais démarre une validation asynchrone sur le disque et vous ne serez pas informé des échecs. Si un autre éditeur de ce SharedPreferences effectue un commit () normal alors qu'un> apply () est toujours en attente, le commit () se bloquera jusqu'à ce que tous les commit asynchrones soient terminés ainsi que le commit lui-même

Vladimir Ivanov
la source
1

La différence entre commit () et apply ()

Nous pouvons être confondus par ces deux termes, lorsque nous utilisons SharedPreference. Fondamentalement, ils sont probablement les mêmes, alors clarifions les différences de commit () et apply ().

1. valeur de retour:

apply()valide sans renvoyer un booléen indiquant un succès ou un échec. commit() retourne vrai si la sauvegarde fonctionne, faux sinon.

  1. La vitesse:

apply()est plus rapide. commit()est plus lent.

  1. Asynchrone vs synchrone:

apply(): Asynchrone commit(): synchrone

  1. Atomique:

apply(): atomique commit(): atomique

  1. Notification d'erreur:

apply(): Non commit(): oui

Chanaka Weerasinghe
la source
Comment est apply()"plus rapide" que commit()? Ils représentent essentiellement une même tâche qui serait mise en Looper du thread. commit()place cette tâche dans le Looper principal tout en la apply()prenant en arrière-plan, gardant ainsi le Looper principal libre de toute tâche d'E / S disque.
Taseer
Contrairement à commit (), qui écrit ses préférences sur le stockage persistant de manière synchrone, apply () valide immédiatement ses modifications dans les SharedPreferences en mémoire, mais démarre une validation asynchrone sur le disque et vous ne serez pas informé des échecs. Si un autre éditeur de ce SharedPreferences effectue un commit () normal alors qu'un apply () est toujours en attente, le commit () se bloquera jusqu'à ce que tous les commit asynchrones soient terminés ainsi que le commit lui-même voir le DOC developer.android.com/reference/ android / content /…
Chanaka Weerasinghe