本文已参与「新人创作礼」活动,一起开启掘金创作之路。
SharedPreferences是Android平台上面的轻量级机制, 来保存和恢复键值对.
SharedPreferences的API过分简化, 使得它的使用因为下面几个原因而受限:
- 类型安全. 调用者必须知道偏好的键和类型.
- 不原生支持自定义数据类型.
- 不支持监听单个键的变化.
RxPreferences构建于SharedPreferences 的基础之上, 修复了这些限制, 并且通过跟RxJava集成从而走的更远.
类型安全的偏好
SharedPreferences要求调用者一直知晓标识偏好的键是什么并且追踪值的类型. 否则的话可能会发生 RuntimeException
.
RxPreferences引入了Preference
类型. 这是个泛化接口, 适用于任何数据类型.
/** A preference of type {@link T}. Instances can be created from {@link RxSharedPreferences}. */
public interface Preference<T> {
......
/** The key for which this preference will store and retrieve values. */
@NonNull String key();
/** The value used if none is stored. */
@NonNull T defaultValue();
/**
* Retrieve the current value for this preference. Returns {@link #defaultValue()} if no value is
* set.
*/
@NonNull T get();
/**
* Change this preference's stored value to {@code value}.
*/
void set(@NonNull T value);
/** Returns true if this preference has a stored value. */
boolean isSet();
/** Delete the stored value for this preference, if any. */
void delete();
......
}
Preference
提供了方法来取代在SharedPreferences
和SharedPreference.Editor
中等价的方法.
RxSharedPreferences
提供了工厂方法将SharedPreferences
绑定到自身, 也提供了方法来操作基础数据类型, 比如Boolean/Enum/Float/Integer/Long/String/Set<String>
.
比如:
SharedPreferences preferences = getDefaultSharedPreferences(this);
RxSharedPreferences rxPrefs = RxSharedPreferences.create(preferences);
Preference<Integer> foo = rxPrefs.getInt("foo");
foo.set(3.14f); // 将不会通过编译!
自定义数据类型
SharedPreferences并没有直接的方法保存和恢复自定义数据类型. 保存时必须手动将Object
转化成String
, 恢复时必须手动将String
转化成Object
, 这是可行的, 但很不方便.
RxPreferences引入了Converter
抽象从任务类型中恢复和检索值, 并且将序列化逻辑放在单独的地方.
/**
* Converts instances of {@code T} to be stored and retrieved as Strings in {@link
* SharedPreferences}.
*/
interface Converter<T> {
/**
* Deserialize to an instance of {@code T}. The input is retrieved from {@link
* SharedPreferences#getString(String, String)}.
*/
@NonNull T deserialize(@NonNull String serialized);
/**
* Serialize the {@code value} to a String. The result will be used with {@link
* SharedPreferences.Editor#putString(String, String)}.
*/
@NonNull String serialize(@NonNull T value);
}
并且, 我们可以使用Gson
或者Moshi
来实现Converter
, 从而序列化自定义数据类型.
举个Gson
的例子:
class GsonPreferenceConverter<T> implements Converter<T> {
final Gson gson;
private Class<T> clazz;
// Constructor and exception handling omitted for brevity.
@Override
public T deserialize(String serialized) {
return gson.fromJson(serialized, clazz);
}
@Override
public String serialize(T value) {
return gson.toJson(value);
}
}
之后RxSharedPreferences.getObject(key, defaultValue, converter)
会将Converter
和Gson
集成.
和RxJava一起使用
SharedPreferences#registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener)
用来监听所有键的变化. 对于特定的键, 调用者必须过滤这个键.
但是来自RxPreferences的Preference<T>
和RxJava
集成可以直接观察单个偏好的变化.
public interface Preference<T> {
/**
* Observe changes to this preference. The current value or {@link #defaultValue()} will be
* emitted on first subscribe.
*/
@CheckResult @NonNull Observable<T> asObservable();
/**
* An action which stores a new value for this preference.
*/
@CheckResult @NonNull Consumer<? super T> asConsumer();
}
所以Preference#asObservable
将Preference
转化成Observable
进行订阅. 之后当Preference
的值发生变化的时候, Observer
将会接到通知.
@Inject @FooPreference BooleanPreference fooPreference;
fooPreference.asObservable()
.subscribe((enabled) -> System.out.println(enabled))
RxBinding
最后, RxPreferences也可以和RxBinding一起工作. 更多信息在这
注意:
RxPreferences是库的名字, 并且RxSharedPreferences
才是具体的类.