PreferenceField

This implementation is able to provide a bit more abstraction by requiring a default value.

Creating it is very similar to the creation of the raw one:

val pref /* : PreferenceField<String> */ = sp.getStringField("pref_key", "default_value")
PreferenceField<String> pref = SharedPreferencesUtils.getStringField(sp, "pref_key", "default_value");

Like its raw counterpart it extends BasePreferenceField, exposing the three already seen properties; the difference is that this time it only implements Field, making it read-only. The value will be the passed default value when the preference is not present.

But why is it read only? It is because having a default value creates some problems due to the value of the field not being exactly the same as the one shared preferences provide.
For example, if the default value is 10 and someone calls pref.value = 10, what is the correct behavior? Remove the preference? Set it to 10? Moreover, given the the lazy nature of fields (i.e. the value doesn't change if it's the same) the value simply wouldn't get saved if the value was already 10.

Changing the value of a PreferenceField

link

In order to modify the value associated with this preference we have two options, exposed through two MutableField properties:

  • rawValue: this field has the same value and behaves exactly has a RawPreferenceField, i.e. it's null when there is no preference set. It is the safest way to change the value, but since its value can be null it might be a bit of an hassle to manage (for instance, calling increment() wouldn't be possible).
  • unsafeMutable: this field adds the default value into the equation, making it easier to manage, but with more problems: in fact setting a value equal to the default one does not guarantee whether the preference will be saved with that value or if it will remain unset. Please notice that is field is a lazy property, so it's initialized upon the first call. Doing this creates a new mutable field that is a two-way transformation of the raw one, so every time this field changes the value will be saved, regardless if it's a default value or not. So once its created, it will affect your preference.

Problems of unsafeMutable

link

You can read more about unsafeMutable behavior in the doc.

Problem 1: unable to remove preference

link
//Initially we suppose there is no value in the preferences val num = sp.getIntField("favorite_number", 73) num.rawValue.value = 10 //Set favorite number to 10, all OK until here num.unsafeMutable.increment() //Increments the favorite number to 11, creating the unsafeMutable in the process //This call now *tries* to remove the preference. The effect is that the preference is removed, the unsafeMutable detects it, //puts as its value the default one (73) and triggers the change of rawValue to 73, which then sets the preference to 73 num.removePreference() val num2 = sp.getIntField("favorite_number", 88) //Same preference, different default value num2.value //Should yield 88, will yield 73
//Initially we suppose there is no value in the preferences PreferenceField<Int> num = SharedPreferencesUtils.getIntField(sp, "favorite_number", 73); num.getRawValue().setValue(10); //Set favorite number to 10, all OK until here IntFieldUtils.increment(num.getUnsafeMutable()); //Increments the favorite number to 11, creating the unsafeMutable in the process //This call now *tries* to remove the preference. The effect is that the preference is removed, the unsafeMutable detects it, //puts as its value the default one (73) and triggers the change of rawValue to 73, which then sets the preference to 73 num.removePreference(); PreferenceField<Int> num2 = SharedPreferencesUtils.getIntField(sp, "favorite_number", 88) //Same preference, different default value num2.getValue() //Should yield 88, will yield 73

Problem 2: unable to save preference with the default value

link
//Initially we suppose there is no value in the preferences val num = sp.getIntField("favorite_number", 73) num.unsafeMutable.value = 73 //The value was already 73 so the change isn't detected and the value is not actually saved val num2 = sp.getIntField("favorite_number", 88) //Same preference, different default value num2.value //Should yield 73, will yield 88
//Initially we suppose there is no value in the preferences PreferenceField<Int> num = SharedPreferencesUtils.getIntField(sp, "favorite_number", 73); num.getUnsafeMutable().setValue(73); //The value was already 73 so the change isn't detected and the value is not actually saved PreferenceField<Int> num2 = SharedPreferencesUtils.getIntField(sp, "favorite_number", 88); num2.getValue(); //Should yield 73, will yield 88

Abstracting more complex values

link

As on the raw counterparts, we can pass two map transformation functions. The null rules are the same and the behavior is the same. For more info see the correspondent section.