Can't put double SharedPreferences

AndroidSharedpreferences

Android Problem Overview


Getting error, the method put double is undefined for this type of sharedPreferences editor.Eclipse is given one quick fix add cast to editor, but when i do that its still given errors, Why cant i put double.

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

Android Solutions


Solution 1 - Android

Those who suggested to use putFloat and getFloat are unfortunately very wrong. Casting a double to a float can result in

  1. Lost precision
  2. Overflow
  3. Underflow
  4. Dead kittens

Those suggesting a toString and parseString are not wrong, but it's an inefficient solution.

The correct way of dealing with this is to convert the double to its 'raw long bits' equivalent and store that long. When you're reading the value, convert back to double.

Because the two data types have the same size you don't lose precision and you won't cause an {over,under}flow.

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

Alternatively you can write the getter as:

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

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

Solution 2 - Android

Kotlin extension way (much more pretty than using weird utils classes or whatever)

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

Solution 3 - Android

What I did was save the preference as a String:

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

and then to retrieve the double, simply use Double.parseDouble:

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

Solution 4 - Android

You could always implement SharedPreferences and wrap the android implementation.

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

Solution 5 - Android

In Kotlin you can convert the double value in a bit representation of the specified floating-point value as Long and then save that bit representation in shared preference with putLong() method. When you want to fetch that value from shared preference just convert it to Double value with Double.fromBits() method and you will have a double value with no precision loss. You can read more about it here.

Here is an example where I use latitude and longitude as a double value within shared preference:

    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 result:

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

Solution 6 - Android

Check this gist https://gist.github.com/john1jan/b8cb536ca51a0b2aa1da4e81566869c4

I have created a Preference Utils class that will handle all the cases.

Its Easy to Use

Storing into preference

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

Getting from preference

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRobertView Question on Stackoverflow
Solution 1 - AndroidcopoliiView Answer on Stackoverflow
Solution 2 - AndroidDima RostopiraView Answer on Stackoverflow
Solution 3 - AndroidJohnView Answer on Stackoverflow
Solution 4 - AndroidbpriceView Answer on Stackoverflow
Solution 5 - AndroidDezoView Answer on Stackoverflow
Solution 6 - AndroidJohnView Answer on Stackoverflow