Instantly share code, notes, and snippets.
Last active
March 22, 2018 17:15
-
Save renaudcerrato/8d55a6b0da5b7cfd3e5b to your computer and use it in GitHub Desktop.
Android's type-safe SharedPreferences: won't throw a ClassCastException anymore if you're calling getLong() instead of getInt(). You can safely call any getter, as long as the value can be converted.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.content.SharedPreferences; | |
import java.util.Map; | |
import java.util.Set; | |
public class TypeSafeSharedPreferences implements SharedPreferences { | |
private final SharedPreferences sharedPreferences; | |
public Map<String, ?> getAll() { | |
return sharedPreferences.getAll(); | |
} | |
public void unregisterOnSharedPreferenceChangeListener(SharedPreferences.OnSharedPreferenceChangeListener listener) { | |
sharedPreferences.unregisterOnSharedPreferenceChangeListener(listener); | |
} | |
public boolean getBoolean(String key, boolean defValue) { | |
try { | |
return sharedPreferences.getBoolean(key, defValue); | |
}catch(ClassCastException e) { | |
return toBoolean(getAll().get(key)); | |
} | |
} | |
public long getLong(String key, long defValue) { | |
try { | |
return sharedPreferences.getLong(key, defValue); | |
}catch(ClassCastException e) { | |
return toLong(getAll().get(key)); | |
} | |
} | |
public boolean contains(String key) { | |
return sharedPreferences.contains(key); | |
} | |
public float getFloat(String key, float defValue) { | |
try{ | |
return sharedPreferences.getFloat(key, defValue); | |
}catch(ClassCastException e) { | |
return (float) toDouble(getAll().get(key)); | |
} | |
} | |
public int getInt(String key, int defValue) { | |
try{ | |
return sharedPreferences.getInt(key, defValue); | |
}catch(ClassCastException e) { | |
return toInteger(getAll().get(key)); | |
} | |
} | |
public void registerOnSharedPreferenceChangeListener(SharedPreferences.OnSharedPreferenceChangeListener listener) { | |
sharedPreferences.registerOnSharedPreferenceChangeListener(listener); | |
} | |
public SharedPreferences.Editor edit() { | |
return sharedPreferences.edit(); | |
} | |
public Set<String> getStringSet(String key, Set<String> defValues) { | |
return sharedPreferences.getStringSet(key, defValues); | |
} | |
public String getString(String key, String defValue) { | |
try { | |
return sharedPreferences.getString(key, defValue); | |
}catch(ClassCastException e) { | |
return String.valueOf(getAll().get(key)); | |
} | |
} | |
public TypeSafeSharedPreferences(SharedPreferences sharedPreferences) { | |
this.sharedPreferences = sharedPreferences; | |
} | |
static boolean toBoolean(Object value) throws ClassCastException { | |
if (value instanceof Boolean) { | |
return (Boolean) value; | |
} else if (value instanceof String) { | |
String stringValue = (String) value; | |
if ("true".equalsIgnoreCase(stringValue)) { | |
return true; | |
} else if ("false".equalsIgnoreCase(stringValue)) { | |
return false; | |
} | |
} | |
try { | |
return toDouble(value) != 0; | |
}catch(ClassCastException e) { | |
throw classCastException(value, "boolean"); | |
} | |
} | |
static double toDouble(Object value) { | |
if (value instanceof Double) { | |
return (Double) value; | |
} else if (value instanceof Number) { | |
return ((Number) value).doubleValue(); | |
} else if (value instanceof String) { | |
try { | |
return Double.valueOf((String) value); | |
} catch (NumberFormatException ignored) { | |
} | |
} | |
throw classCastException(value, "double"); | |
} | |
static int toInteger(Object value) { | |
if (value instanceof Integer) { | |
return (Integer) value; | |
} else if (value instanceof Number) { | |
return ((Number) value).intValue(); | |
} else if (value instanceof String) { | |
try { | |
return (int) Double.parseDouble((String) value); | |
} catch (NumberFormatException ignored) { | |
} | |
} | |
throw classCastException(value, "integer"); | |
} | |
static long toLong(Object value) { | |
if (value instanceof Long) { | |
return (Long) value; | |
} else if (value instanceof Number) { | |
return ((Number) value).longValue(); | |
} else if (value instanceof String) { | |
try { | |
return (long) Double.parseDouble((String) value); | |
} catch (NumberFormatException ignored) { | |
} | |
} | |
throw classCastException(value, "long"); | |
} | |
static String toString(Object value) { | |
if (value instanceof String) { | |
return (String) value; | |
} else if (value != null) { | |
return String.valueOf(value); | |
} | |
throw classCastException(value, "string"); | |
} | |
private static ClassCastException classCastException(Object value, String type) { | |
return new ClassCastException(value + " cannot be casted to " + type); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.content.Context; | |
import android.content.SharedPreferences; | |
import android.preference.PreferenceManager; | |
import android.support.test.InstrumentationRegistry; | |
import android.support.test.runner.AndroidJUnit4; | |
import org.junit.Before; | |
import org.junit.Test; | |
import org.junit.runner.RunWith; | |
import static junit.framework.Assert.assertEquals; | |
@RunWith(AndroidJUnit4.class) | |
public class TestTypeSafeSharedPreferences { | |
private SharedPreferences mSharedPref; | |
@Before | |
public void setup() throws Exception { | |
Context context = InstrumentationRegistry.getTargetContext(); | |
mSharedPref = new TypeSafeSharedPreferences(PreferenceManager.getDefaultSharedPreferences(context)); | |
} | |
@Test | |
public void testLong() { | |
clear(); | |
mSharedPref.edit().putLong("long", 42).apply(); | |
test("long", 42); | |
test("long", 42L); | |
test("long", 42f); | |
} | |
@Test | |
public void testInt() { | |
clear(); | |
mSharedPref.edit().putInt("int", 42).apply(); | |
test("int", 42); | |
test("int", 42L); | |
test("int", 42f); | |
} | |
@Test | |
public void testFloat() { | |
clear(); | |
mSharedPref.edit().putFloat("float", 42).apply(); | |
test("float", 42); | |
test("float", 42L); | |
test("float", 42f); | |
} | |
@Test | |
public void testString() { | |
clear(); | |
mSharedPref.edit().putString("string", "42").apply(); | |
test("string", 42); | |
test("string", 42L); | |
test("string", 42f); | |
} | |
@SuppressWarnings("ConstantConditions") | |
private void test(String key, int value) { | |
assertEquals(value, mSharedPref.getInt(key, 0)); | |
assertEquals((long)value, mSharedPref.getLong(key, 0)); | |
assertEquals((float)value, mSharedPref.getFloat(key, 0)); | |
assertEquals(value, (int) (double) Double.parseDouble(mSharedPref.getString(key, null))); | |
assertEquals(value != 0, mSharedPref.getBoolean(key, value == 0)); | |
} | |
@SuppressWarnings("ConstantConditions") | |
private void test(String key, long value) { | |
assertEquals((int) value, mSharedPref.getInt(key, 0)); | |
assertEquals(value, mSharedPref.getLong(key, 0)); | |
assertEquals((float)value, mSharedPref.getFloat(key, 0)); | |
assertEquals(value, (long) (double) Double.parseDouble(mSharedPref.getString(key, null))); | |
assertEquals(value != 0, mSharedPref.getBoolean(key, value == 0)); | |
} | |
@SuppressWarnings("ConstantConditions") | |
private void test(String key, float value) { | |
assertEquals((int)value, mSharedPref.getInt(key, 0)); | |
assertEquals((long)value, mSharedPref.getLong(key, 0)); | |
assertEquals(value, mSharedPref.getFloat(key, 0)); | |
assertEquals(value, (float) (double) Double.parseDouble(mSharedPref.getString(key, null))); | |
assertEquals(value != 0, mSharedPref.getBoolean(key, value == 0)); | |
} | |
private void clear() { | |
mSharedPref.edit().clear().apply(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment