Nie można umieścić podwójnych SharedPreferences

90

Pojawia się błąd, metoda put double jest niezdefiniowana dla tego typu edytora sharedPreferences.Eclipse ma jedną szybką poprawkę dodaj rzut do edytora, ale kiedy to robię, nadal pojawiają się błędy, Dlaczego nie mogę umieścić podwójnie.

Kod:

@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
źródło
2
czy możesz określić, jaki masz błąd?
dumbfingers
1
Spójrz na pierwszą linię pytania
Robert
Zastanawiam się, jak to się dzieje, że androidy nie zaimplementowały putDouble w API?
luky

Odpowiedzi:

336

Ci, którzy zasugerowali użycie putFloat i getFloat, są niestety bardzo w błędzie. Rzucenie double na float może skutkować

  1. Utrata precyzji
  2. Przelewowy
  3. Niedomiar
  4. Martwe kocięta

Te, które sugerują toString i parseString, nie są w błędzie, ale jest to nieefektywne rozwiązanie.

Prawidłowym sposobem radzenia sobie z tym jest zamiana podwójnego na jego odpowiednik „surowych długich bitów” i zapisanie takiej długości. Kiedy odczytujesz wartość, zamień z powrotem na double.

Ponieważ te dwa typy danych mają ten sam rozmiar, nie tracisz precyzji i nie spowodujesz przepływu {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)));
}

Alternatywnie możesz napisać getter jako:

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
źródło
9
Tak piękny, czysty i elegancki.
Bogdan Alexandru,
9
Metoda putDouble byłaby nadal przyjemna i spójna z innym interfejsem API w ekosystemie Androida (takim jak parceable i pakiety). Typowy przypadek, gdy Google znów jest szybki i niechlujny.
2
dlaczego zapisywanie go jako łańcucha jest nieefektywne?
KKO
2
@KKO Typ danych long to 64-bitowa liczba całkowita z uzupełnieniem do dwóch. Więc zajmuje tylko 4 bajty. Ale jeśli przechowujesz tę doublewartość jako ciąg, zrujnujesz swój magazyn i sprawisz, że stanie się wrakiem!
semsamot
1
prefs.getLong (klucz, 0d) niepoprawnie to nie jest podwójna. powinno być bez d.
Ahmed Hegazy
27

Sposób rozszerzenia Kotlin (znacznie ładniejszy niż używanie dziwnych klas narzędzi lub cokolwiek innego)

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
źródło
2
Świetnie, dokładnie myślałem o umieszczeniu tego tutaj. Dzięki!
wzieba
16

Zapisałem preferencję jako ciąg:

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

a następnie, aby pobrać double, po prostu użyj Double.parseDouble:

Double.parseDouble(getSharedPreferences("PREFERENCE", MODE_PRIVATE).getString("double", "0.01"));
Jan
źródło
4
Marnujesz pamięć. Jest również znacznie wolniejszy niż doubleToRawLongBitsmetoda, o której już wspomniano. To jest zły sposób, nie dlatego, że nie zadziała, ale dlatego, że jest bardzo nieefektywny.
copolii
10
@copolii Z naukowego punktu widzenia, jasne. Praktycznie w przemyśle to naprawdę nie robi wystarczającej różnicy, aby mieć znaczenie w 99% przypadków, aw rzeczywistości jest to prawdopodobnie bardziej czytelne i łatwiejsze do zrozumienia, gdy sprowadza się kogoś nowego.
Dennis L
@DennisL #PracticalDev
Aba
9

Zawsze możesz zaimplementować SharedPreferences i opakować implementację Androida.

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
    }
}
bcena
źródło
To jest poprawna odpowiedź. Żałuję, że nie widziałem tego, zanim zacząłem pisać. Czy nie byłoby bardziej wydajne zwrócenie „this” w metodach edytora? Oszczędza ci to wywoływania metody „instanceof”. A może próbowałeś tego i spowodowało to problemy?
copolii
0

Sprawdź sedno https://gist.github.com/john1jan/b8cb536ca51a0b2aa1da4e81566869c4

Stworzyłem klasę Preference Utils, która będzie obsługiwać wszystkie przypadki.

Jest łatwy w użyciu

Przechowywanie według preferencji

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

Pierwszeństwo z preferencji

Double income = (Double) PrefUtils.getFromPrefs(getActivity(), PrefKeys.USER_INCOME, new Double(10));
Jan
źródło