What's the point of having a default value in sharedPref.getString?
Consider this in a such way:
Every String
preference in SharedPreferences
can exist or not and can be null
or not. So the code
val lat: String = sharedPref.getString("MyKey", "Default") ?: "Not Set"
will return:
Default
if the preference with this Key doesn't exists (means there is no mapping for this Key)Not Set
if the preference exists, but isnull
(mapping Key tonull
created)- any other
value
if the preference exists and the value of the mapping isn'tnull
.
Update
Apparently, SharedPreferences are much less smart I thought it was. Having this code internally:
String v = (String)mMap.get(key);
return v != null ? v : defValue;
it will return null
only if we'll pass null
as a default value (and there were no value saved). This means we actually don't need an elvis option and we will not get "Not Set"
value. This method returns nullable value, just because it allows you to pass nullable as a default value.
It's because kotlin Null-Safety is kick in when reading the following code:
val lat: String = sharedPref.getString("MyKey", "Default")
if you visit the SharedPreferences code, you can see the following code:
@Nullable
String getString(String key, @Nullable String defValue);
which is give us a probability to use null as defValue
parameter. So, Kotlin try to guard it and give you the matching error:
"Type mismatch. Required String, found String?"
You can fix the problem by enabling nullable for your String variable with:
val lat: String? = sharedPref.getString("MyKey", "Default")
though this against Kotlin type system purpose:
Kotlin's type system is aimed at eliminating the danger of null references from code, also known as the The Billion Dollar Mistake.
SharedPreferences
is an abstraction over Key/Value databasing provided by Google, how you use it is up to you. If you dislike this syntax, then create a wrapper or extension for your getString()
. Just to give an example:
fun PreferenceManager.getStringTheFancyWay(key: String, defaultValue: String): String {
return getString(key, defaultValue) ?: defaultValue
}
val value = getStringTheFancyWay("a", "b")
Personally I dislike this, because null
allows for a better control flow over non-existing keys.
This is how I use SharedPreferences
val preferences = PreferenceManager.getDefaultSharedPreferences(context)
val value = preferences.getString("username", null)
if (value != null) {
toast("Hello $value")
} else {
toast("Username not found")
}
or
preferences.getString("username", null)?.let { username ->
toast("Hello $username")
}
Notice the difference?