无法使用双重SharedPreferences

100

出现错误,sharedPreferences编辑器类型未定义putDouble方法。Eclipse提供了一个快速修复方法将编辑器添加到强制转换中,但是当我这样做时仍然会出现错误,为什么不能putDouble。

代码:

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

2
请问您能具体说明一下您遇到了什么错误吗? - dumbfingers
1
查看问题的第一行 - Robert
1
我想知道为什么Android开发人员没有在API中实现putDouble方法? - luky
6个回答

359

那些建议使用putFloatgetFloat的人很不幸是错的。将double强制转换为float可能会导致:

  1. 精度丢失
  2. 溢出
  3. 下溢
  4. 猫死亡

建议使用toStringparseString的人没有错,但这是一种效率低下的解决方案。

正确的处理方式是将double转换为其“原始长位”等效值并存储该长整型。在读取值时,转换回double。

因为两种数据类型具有相同的大小,所以您不会失去精度,也不会引起{上溢、下溢}。

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

或者你可以将getter写成:

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

return Double.longBitsToDouble(prefs.getLong(key, 0));
}

10
非常美丽,干净优雅。 - Bogdan Alexandru
10
尽管在Android生态系统中(如Parcelable和Bundles)已经有其他API,但拥有一个putDouble方法仍然是一个很好且一致的选择。这是Google再次快速而马虎的典型案例。 - user458577
2
为什么将它保存为字符串是低效的? - KKO
2
@KKO 长整型是一个64位的二进制补码整数。因此,它只需要4个字节。但是,如果您将该“double”值存储为字符串,则会破坏您的存储并使其成为废墟! - semsamot
1
prefs.getLong(key, 0) 不正确,它不是 double 类型。应该去掉 d。 - Ahmed Hegazy
显示剩余5条评论

43

Kotlin扩展方式(比使用奇怪的utils类或其他方式更加优美)

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

2
太好了,我正想把它放在这里。谢谢! - wzieba
如何将数据存储到变量中?有人可以帮助我吗? - Mohan

19

我所做的是将偏好保存为字符串:

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

然后要取回double,只需使用Double.parseDouble:

Double.parseDouble(getSharedPreferences("PREFERENCE", MODE_PRIVATE).getString("double", "0.01"));

4
您浪费了存储空间。而且这种方法比已经提到的doubleToRawLongBits方法慢得多。这是错误的方法,不是因为它不能运行,而是因为它非常低效。 - copolii
11
学术上来说没错。但实际应用到行业中,99%的情况下这并没有太大区别,事实上,这样写可能更易读懂,更容易让新人理解。 - Dennis L
@DennisL #实用开发者 - Aba

9
你可以使用SharedPreferences来实现,并包装安卓的实现。
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
    }
}

这是正确的答案。我希望在我开始打字之前就看到了它。在编辑器方法中只返回“this”是否更有效率?这样可以避免调用“instanceof”方法。或者你尝试过这样做,但出现了问题吗? - copolii

0

查看这个代码片段 https://gist.github.com/john1jan/b8cb536ca51a0b2aa1da4e81566869c4

我创建了一个Preference Utils类,它将处理所有情况。

使用起来非常容易

存储到首选项中

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

从偏好获取

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

0
在Kotlin中,您可以将双精度值转换为指定浮点值的位表示形式作为Long,并使用putLong()方法将该位表示形式保存在共享首选项中。当您想从共享首选项中获取该值时,只需使用Double.fromBits()方法将其转换为Double值,您将获得没有精度损失的双精度值。您可以在此处阅读更多信息here
以下是一个示例,在其中我将纬度和经度作为双精度值存储在共享首选项中:
    val lat: Double = 40.23244412709637
    val lng: Double = 14.280891281901097
    
     private fun saveFetchedLocation(lat: Double, lng: Double) {
            val sharedPreference: SharedPreferences = requireActivity().getSharedPreferences(
                SHARED_PREF,
                Context.MODE_PRIVATE
            )
            val editor: SharedPreferences.Editor = sharedPreference.edit()
            editor.apply {
                putLong("lat_value", lat.toBits())
                putLong("lng_val", lng.toBits())
     
            Log.i("Tag", "LONG_BITS: "+ " Lat: " + lat.toBits() + " Lng: " + lng.toBits())
    
            }.apply()
    
        }
    
    private fun loadPreferences() {
            val sharedPreference: SharedPreferences = requireActivity().getSharedPreferences(
                SHARED_PREF,
                Context.MODE_PRIVATE
            )
            val lat_double: Double = Double.fromBits(sharedPreference.getLong("lat_value", 1))
            val lng_double: Double = Double.fromBits(sharedPreference.getLong("lng_val", 1))
    
            Log.i("Tag", "FINAL_DOUBLE: $lat_double and $lng_double")
    
        }

Logcat 结果:
//bit representation of the specified floating-point values as Long
I/Tag: LONG_BITS:  Lat: 4630859030446343002 Lng: 4624229045136719443 

//converted double values with no precision loss
I/Tag: FINAL_DOUBLE: 40.23244412709637 and 14.280891281901097

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接