现状
有很多Preference来自于某些对象的字段,这些字段的存储其实非常繁琐,每增加一个字段,需要修改3个地方:
- key
- 对象字段
- 对象内容的存储
目标是搞成单点修改,但是:
- 受限于java的Annotation限制很多,对于泛型、继承支持不太好,很难优雅的实现default value
- 不太想做AnnotationProcessor(使用生成代码,可以把key映射成方法名,get的时候不需要key,此时可以做到依靠annotation,单点修改)
最后定成两点修改:
- 定义enum作为key
- 定义annotation进行自动化
代码
核心utils
public class PreferenceAnnotationUtils {
public interface PersistProvider {
String getKey();
Object getDef();
boolean isUser();
}
public static <T extends Annotation> void save(Object object,
SharedPreferences preferences, Function<T, PersistProvider> func,
Class<T> annotation) {
Field[] fields = object.getClass().getFields();
for (Field field : fields) {
T annotationInstance = field.getAnnotation(annotation);
if (annotationInstance == null) {
continue;
}
PersistProvider provider = func.apply(annotationInstance);
if (provider == null) {
continue;
}
try {
Object value = field.get(object);
String prefKey =
provider.isUser() ? KwaiApp.ME.getId() + provider.getKey() : provider.getKey();
if (value == null) {
continue;
}
if (value.getClass() == String.class) {
preferences.edit().putString(prefKey, (String) value).apply();
} else if (value.getClass() == int.class || value.getClass() == Integer.class) {
if (provider.getDef().getClass() == boolean.class
|| provider.getDef().getClass() == Boolean.class) {
preferences.edit().putBoolean(prefKey, (Integer) value == 1).apply();
} else {
preferences.edit().putInt(prefKey, (Integer) value).apply();
}
} else if (value.getClass() == boolean.class || value.getClass() == Boolean.class) {
preferences.edit().putBoolean(prefKey, (Boolean) value).apply();
} else if (value.getClass() == float.class || value.getClass() == Float.class) {
preferences.edit().putFloat(prefKey, (Float) value).apply();
} else if (value.getClass() == long.class || value.getClass() == Long.class) {
preferences.edit().putLong(prefKey, (Long) value).apply();
} else {
preferences.edit().putString(prefKey, Gsons.KWAI_GSON.toJson(value)).apply();
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
定义annotation
public @interface MainPreferencePersist {
MainPrefKey value();
}
public enum MainPrefKey implements PreferenceAnnotationUtils.PersistProvider {
...
}
定义映射
public class Foo{
@MainPreferencePersist(BAR)
public boolean mBar;
...
}
使用
Foo foo = getFoo();
PreferenceAnnotationUtils.save(foo, getPref(),
new Function<MainPreferencePersist, PreferenceAnnotationUtils.PersistProvider>() {
@Nullable
@Override
public PreferenceAnnotationUtils.PersistProvider apply(
@Nullable MainPreferencePersist input) {
return input.value();
}
}, MainPreferencePersist.class);
其实思路就是ORM的保存,但是要做自动化。
其他库
经提醒,发现线上是有其他库做Preference 的ORM库的,而且有很大的:
- androidannotation:主要关注的是preference的强类型话,定义的是interface
- android-prefs:关注点是把Preference改成一个POJO
二者稍稍修改就能做到自动保存,不过为此引一个库并不划算。
续
后面又因为种种原因做起来代码生成,最后的库。