Impossible de mettre les doubles SharedPreferences

90

Obtenir une erreur, la méthode put double n'est pas définie pour ce type d'éditeur sharedPreferences.Eclipse reçoit un correctif rapide ajouter un cast à l'éditeur, mais quand je le fais, ses erreurs sont encore données, pourquoi je ne peux pas mettre double

Le code:

@Override
protected void onPause() {
    // TODO Auto-generated method stub
    super.onPause();

    if (TextUtils.isEmpty(editBl.getText().toString())) {
        numberOfBl = 0;
    } else {
        numberOfBl = Integer.parseInt(editBl.getText().toString();

    }
    if (TextUtils.isEmpty(editSt.getText().toString())) {
        tonOfSt = 0;
    } else {
        tonOfSt = Double.parseDouble(editSt.getText().toString());

    }

    SharedPreferences prefs = getSharedPreferences(
            "SavedTotals", Context.MODE_PRIVATE);

    SharedPreferences.Editor editor = prefs.edit();

    editor.putInt("savedBl", numberOfBl);
    editor.putDouble("savedSt", tonOfSt);


    editor.commit();
}
Robert
la source
2
pourriez-vous s'il vous plaît préciser quelle erreur vous avez?
dumbfingers
1
Regardez la première ligne de la question
Robert
Je me demande comment se fait-il que les gars d'Android n'aient pas implémenté putDouble dans l'API?
luky

Réponses:

336

Ceux qui ont suggéré d'utiliser putFloat et getFloat se trompent malheureusement. Lancer un double sur un flotteur peut entraîner

  1. Précision perdue
  2. Débordement
  3. Dépassement
  4. Chatons morts

Ceux qui suggèrent une toString et une parseString ne sont pas faux, mais c'est une solution inefficace.

La bonne façon de gérer cela est de convertir le double en son équivalent «bits longs bruts» et de stocker ce long. Lorsque vous lisez la valeur, convertissez-la en double.

Étant donné que les deux types de données ont la même taille, vous ne perdez pas de précision et vous ne provoquerez pas de flux {over, under}.

Editor putDouble(final Editor edit, final String key, final double value) {
   return edit.putLong(key, Double.doubleToRawLongBits(value));
}

double getDouble(final SharedPreferences prefs, final String key, final double defaultValue) {
return Double.longBitsToDouble(prefs.getLong(key, Double.doubleToLongBits(defaultValue)));
}

Vous pouvez également écrire le getter comme suit:

double getDouble(final SharedPreferences prefs, final String key, final double defaultValue) {
if ( !prefs.contains(key))
        return defaultValue;

return Double.longBitsToDouble(prefs.getLong(key, 0));
}
copolii
la source
9
Si beau, propre et élégant.
Bogdan Alexandru
9
Une méthode putDouble serait toujours agréable et cohérente avec d'autres API de l'écosystème Android (comme parceable et bundles). Un cas typique de Google étant à nouveau rapide et bâclé.
2
pourquoi l'enregistrer sous forme de chaîne est inefficace?
KKO
2
@KKO Le type de données long est un entier complémentaire à deux de 64 bits. Donc, cela ne prend que 4 octets. Mais si vous stockez cette doublevaleur sous forme de chaîne, vous ruinez votre stockage et en faites une épave !!
semsamot
1
prefs.getLong (key, 0d) incorrect ce n'est pas un double. devrait être sans le d.
Ahmed Hegazy
27

Méthode d'extension Kotlin (beaucoup plus jolie que d'utiliser des classes d'utils étranges ou autre)

fun SharedPreferences.Editor.putDouble(key: String, double: Double) =
    putLong(key, java.lang.Double.doubleToRawLongBits(double))

fun SharedPreferences.getDouble(key: String, default: Double) =
    java.lang.Double.longBitsToDouble(getLong(key, java.lang.Double.doubleToRawLongBits(default)))
Dima Rostopira
la source
2
Super, je pensais exactement à mettre ça ici. Merci!
wzieba
16

Ce que j'ai fait, c'est enregistrer la préférence sous forme de chaîne:

getSharedPreferences("PREFERENCE", MODE_PRIVATE).edit().putString("double", "0.01").commit();

puis pour récupérer le double, utilisez simplement Double.parseDouble:

Double.parseDouble(getSharedPreferences("PREFERENCE", MODE_PRIVATE).getString("double", "0.01"));
John
la source
4
Vous gaspillez du stockage. C'est aussi beaucoup plus lent que la doubleToRawLongBitsméthode déjà mentionnée. Ce n'est pas la bonne façon, non pas parce que cela ne fonctionnera pas, mais parce que c'est très inefficace.
copolii
10
@copolii Académiquement, bien sûr. Pratiquement, dans l'industrie, cela ne fait vraiment pas assez de différence pour avoir de l'importance dans 99% des cas et en fait, c'est probablement plus lisible et plus facile à comprendre lorsqu'on fait venir quelqu'un de nouveau.
Dennis L
@DennisL #PracticalDev
Aba
9

Vous pouvez toujours implémenter SharedPreferences et encapsuler l'implémentation Android.

package com.company.sharedpreferences;

import android.content.Context;
import android.content.SharedPreferences;


import java.util.Map;
import java.util.Set;

public class EnhancedSharedPreferences implements SharedPreferences {

    public static class NameSpaces {
        public static String MY_FUN_NAMESPACE = "MyFunNameSpacePrefs";
    }

    public static EnhancedSharedPreferences getPreferences(String prefsName) {
        return new EnhancedSharedPreferences(SomeSingleton.getInstance().getApplicationContext().getSharedPreferences(prefsName, Context.MODE_PRIVATE));
    }

    private SharedPreferences _sharedPreferences;

    public EnhancedSharedPreferences(SharedPreferences sharedPreferences) {
        _sharedPreferences = sharedPreferences;
    }

    //region Overrides

    @Override
    public Map<String, ?> getAll() {
        return _sharedPreferences.getAll();
    }

    @Override
    public String getString(String key, String defValue) {
        return _sharedPreferences.getString(key, defValue);
    }

    @Override
    public Set<String> getStringSet(String key, Set<String> defValues) {
        return _sharedPreferences.getStringSet(key, defValues);
    }

    @Override
    public int getInt(String key, int defValue) {
        return _sharedPreferences.getInt(key, defValue);
    }

    @Override
    public long getLong(String key, long defValue) {
        return _sharedPreferences.getLong(key, defValue);
    }

    @Override
    public float getFloat(String key, float defValue) {
        return _sharedPreferences.getFloat(key, defValue);
    }

    @Override
    public boolean getBoolean(String key, boolean defValue) {
        return _sharedPreferences.getBoolean(key, defValue);
    }

    @Override
    public boolean contains(String key) {
        return _sharedPreferences.contains(key);
    }

    @Override
    public Editor edit() {
        return new Editor(_sharedPreferences.edit());
    }

    @Override
    public void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
        _sharedPreferences.registerOnSharedPreferenceChangeListener(listener);
    }

    @Override
    public void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
        _sharedPreferences.unregisterOnSharedPreferenceChangeListener(listener);
    }

    //endregion

    //region Extension

    public Double getDouble(String key, Double defValue) {
        return Double.longBitsToDouble(_sharedPreferences.getLong(key, Double.doubleToRawLongBits(defValue)));
    }

    //endregion

    public static class Editor implements SharedPreferences.Editor {

        private SharedPreferences.Editor _editor;

        public Editor(SharedPreferences.Editor editor) {
            _editor = editor;
        }

        private Editor ReturnEditor(SharedPreferences.Editor editor) {
            if(editor instanceof Editor)
                return (Editor)editor;
            return new Editor(editor);
        }

        //region Overrides

        @Override
        public Editor putString(String key, String value) {
            return ReturnEditor(_editor.putString(key, value));
        }

        @Override
        public Editor putStringSet(String key, Set<String> values) {
            return ReturnEditor(_editor.putStringSet(key, values));
        }

        @Override
        public Editor putInt(String key, int value) {
            return ReturnEditor(_editor.putInt(key, value));
        }

        @Override
        public Editor putLong(String key, long value) {
            return ReturnEditor(_editor.putLong(key, value));
        }

        @Override
        public Editor putFloat(String key, float value) {
            return ReturnEditor(_editor.putFloat(key, value));
        }

        @Override
        public Editor putBoolean(String key, boolean value) {
            return ReturnEditor(_editor.putBoolean(key, value));
        }

        @Override
        public Editor remove(String key) {
            return ReturnEditor(_editor.remove(key));
        }

        @Override
        public Editor clear() {
            return ReturnEditor(_editor.clear());
        }

        @Override
        public boolean commit() {
            return _editor.commit();
        }

        @Override
        public void apply() {
            _editor.apply();
        }

        //endregion

        //region Extensions

        public Editor putDouble(String key, double value) {
            return new Editor(_editor.putLong(key, Double.doubleToRawLongBits(value)));
        }

        //endregion
    }
}
bprice
la source
C'est la bonne réponse. J'aurais aimé voir cela avant de commencer à taper. Ne serait-il pas plus efficace de simplement renvoyer «this» dans les méthodes de l'éditeur? Cela vous évite d'appeler la méthode 'instanceof'. Ou avez-vous essayé cela et cela a causé des problèmes?
copolii
0

Vérifiez cet essentiel https://gist.github.com/john1jan/b8cb536ca51a0b2aa1da4e81566869c4

J'ai créé une classe Preference Utils qui gérera tous les cas.

C'est facile à utiliser

Stockage dans les préférences

PrefUtils.saveToPrefs(getActivity(), PrefKeys.USER_INCOME, income);

Obtenir de la préférence

Double income = (Double) PrefUtils.getFromPrefs(getActivity(), PrefKeys.USER_INCOME, new Double(10));
John
la source