web-dev-qa-db-fra.com

Utiliser SharedPreferences en mode multi-processus

J'ai défini une instance de SharedPreferences utilisée en mode multi-processus. 

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
}

Maintenant, j'utilise cette classe sur un service avec un processus séparé et également dans mon processus d'application principal de manière statique.
Tout va bien, mais parfois toutes les données stockées sur l'instance SharedPreferences sont supprimées!
Comment puis-je résoudre ce problème?

Edit: Enfin, j'ai résolu mon problème en utilisant IPC.

17
Mousa Jafari

Il n’existe actuellement aucun moyen d’accéder en toute sécurité à SharedPreferences sur plusieurs processus, comme indiqué dans sa documentation .

Remarque: Cette classe ne prend pas en charge l'utilisation sur plusieurs processus.

Après avoir beaucoup testé avec MODE_MULTI_PROCESS, j'ai trois essais à partager:

1- Initialise la SharedPreferences une fois dans chaque processus et l'utilise plusieurs fois.

Le problème: Les valeurs ne sont pas reflétées dans chaque processus comme prévu. Ainsi, chaque processus a sa propre valeur de SharedPreferences.

2- Initialise la SharedPreferences dans chaque put ou get.

Cela fonctionne réellement et la valeur est maintenant interchangeable entre les processus.

Le problème: parfois après avoir accédé agressivement à sharedpref, le fichier de préférences partagées a été supprimé avec tout son contenu, comme décrit dans ce issue , et cet avertissement apparaît dans le bûche:

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)

Vous pouvez trouver pourquoi cela se produit dans le numéro.

3- Utilisez la synchronisation pour verrouiller les méthodes qui mettent et obtiennent des valeurs dans la variable SharedPreferences.

C'est complètement faux. la synchronisation ne fonctionne pas entre les processus. La SharedPreferences utilise effectivement la synchronisation dans son implémentation, mais cela ne fait que garantir la sécurité des threads, pas la sécurité des processus. Ceci est très bien décrit ici .

31
Ahmed Hegazy

SharedPreferences en soi n'est pas sûr pour le processus. C'est probablement pourquoi Documentation SharedPreferences dit

Remarque: actuellement, cette classe ne prend pas en charge l'utilisation sur plusieurs processus. Ce sera ajouté plus tard.

6
VikramV

L'utilisation de la méthode commit() enregistre les modifications dans le stockage persistant. Par conséquent, il est lent et crée des conflits entre plusieurs appels provenant d'autres processus.

Cependant, il existe une alternative à cette méthode. Vous devez appeler la méthode apply(). Cette méthode stocke les modifications en mémoire, puis dans le stockage sur disque de manière asynchrone, ce qui la rend plus fiable.

3
M. Reza Nasirloo

J'ai travaillé autour de cela en combinant:

  • Fournir à chaque processus un accès mutuellement exclusif au fichier SharedPreferences (par exemple, en utilisant un mécanisme de verrouillage basé sur une socket )
  • Réinitialiser la SharedPreferences avec l'indicateur MODE_MULTI_PROCESS chaque fois que vous voulez l'utiliser pour contourner la mise en cache en mémoire

Cela semble fonctionner correctement, mais cela n’a pas été complètement testé dans le monde réel, donc je ne sais pas s’il est parfaitement fiable.

Vous pouvez voir un exemple de travail que j'ai écrit ici .

Avertissement : On dirait que MODE_MULTI_PROCESS est obsolète dans Android M. Il pourrait ne plus fonctionner dans le futur.

3
Sam

rappelle que l'utilisation d'objets de contexte en tant que champ statique entraîne un risque de fuite du contexte, car elle ne déclare pas l'objet dans la classe d'application

public class CustomApplication extends Application{
     private Prefs prefs;

     public void onCreate(){
          prefs = new Prefs(this);
     }

     public Prefs getPrefs(){
        return prefs;
     }
}

De n'importe quel contexte, vous pouvez obtenir les préfs

   ((MyApplication)context.getApplicationContext()).getPrefs();
1
Fernando Quintal

Utilisez un fournisseur de contenu utilisant SharedPreferences. Exemple, voir ici: https://github.com/hamsterksu/MultiprocessPreferences

0
Highriser