Doppelte SharedPreferences können nicht gesetzt werden

90

Wenn ein Fehler auftritt, ist die Methode put double für diesen Typ von sharedPreferences-Editor undefiniert. Eclipse erhält eine Schnellkorrektur zum Hinzufügen von Cast zum Editor, aber wenn ich das tue, werden immer noch Fehler angezeigt. Warum kann ich double nicht setzen?

Der 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
quelle
2
Könnten Sie bitte angeben, welchen Fehler Sie haben?
Dummköpfe
1
Schauen Sie sich die erste Zeile der Frage an
Robert
Ich frage mich, wie kommt es, dass Android-Jungs putDouble nicht in API implementiert haben?
luky

Antworten:

334

Diejenigen, die vorgeschlagen haben, putFloat und getFloat zu verwenden, liegen leider sehr falsch. Das Werfen eines Double auf einen Float kann dazu führen

  1. Verlorene Präzision
  2. Überlauf
  3. Unterlauf
  4. Tote Kätzchen

Diejenigen, die einen toString und einen parseString vorschlagen, sind nicht falsch, aber es ist eine ineffiziente Lösung.

Der richtige Weg, damit umzugehen, besteht darin, das Double in sein Äquivalent "Raw Long Bits" umzuwandeln und so lange zu speichern. Wenn Sie den Wert lesen, konvertieren Sie zurück in double.

Da die beiden Datentypen dieselbe Größe haben, verlieren Sie nicht an Genauigkeit und verursachen keinen {over, under} -Fluss.

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)));
}

Alternativ können Sie den Getter wie folgt schreiben:

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
quelle
9
So schön, sauber und elegant.
Bogdan Alexandru
9
Eine putDouble-Methode wäre trotzdem nett und konsistent mit anderen APIs im Android-Ökosystem (wie Parceable und Bundles). Ein typischer Fall, in dem Google wieder schnell und schlampig ist.
2
Warum ist das Speichern als Zeichenfolge ineffizient?
KKO
2
@KKO Der lange Datentyp ist eine 64-Bit-Zweierkomplement-Ganzzahl. Es dauert also nur 4 Bytes. Aber wenn Sie diesen doubleWert als Zeichenfolge speichern, ruinieren Sie Ihren Speicher und machen ihn zu einem Wrack !!
Semsamot
1
prefs.getLong (key, 0d) falsch, es ist kein Double. sollte ohne die d sein.
Ahmed Hegazy
25

Kotlin-Erweiterungsmethode (viel hübscher als die Verwendung von seltsamen Utils-Klassen oder was auch immer)

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
quelle
2
Großartig, ich habe genau darüber nachgedacht, dies hier zu platzieren. Vielen Dank!
Wzieba
16

Was ich getan habe, war die Einstellung als String zu speichern:

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

und um das Double abzurufen, verwenden Sie einfach Double.parseDouble:

Double.parseDouble(getSharedPreferences("PREFERENCE", MODE_PRIVATE).getString("double", "0.01"));
John
quelle
4
Sie verschwenden Speicherplatz. Es ist auch viel langsamer als die doubleToRawLongBitsbereits erwähnte Methode. Dies ist der falsche Weg, nicht weil es nicht funktioniert, sondern weil es sehr ineffizient ist.
Copolii
10
@copolii Akademisch sicher. In der Industrie macht es praktisch nicht genug aus, um in 99% der Fälle eine Rolle zu spielen, und tatsächlich ist dies wahrscheinlich besser lesbar und leichter zu verstehen, wenn jemand neu eingestellt wird.
Dennis L
@ TennisL #PracticalDev
Aba
9

Sie können SharedPreferences jederzeit implementieren und die Android-Implementierung umbrechen.

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
    }
}
Preis
quelle
Dies ist die richtige Antwort. Ich wünschte, ich hätte das gesehen, bevor ich anfing zu tippen. Wäre es nicht effizienter, "dies" in den Editor-Methoden zurückzugeben? Es erspart Ihnen den Aufruf der Methode 'instanceof'. Oder haben Sie das versucht und es hat Probleme verursacht?
Copolii
0

Überprüfen Sie diese Liste https://gist.github.com/john1jan/b8cb536ca51a0b2aa1da4e81566869c4

Ich habe eine Preference Utils-Klasse erstellt, die alle Fälle behandelt.

Es ist einfach zu bedienen

In Vorlieben speichern

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

Von der Präferenz kommen

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