布景

源于深夜一段独白:

Key Value 界说几十上百个是常见事,现在有更简练方式么,

此为项目中为数不多不受操控之地,指数膨胀,且易埋下共同性隐患,

每新增一 value,需兼顾 key、get、put、init,5 处 …

public class Configs {
 
  ...
  
 private static int TEST_ID;
 
 public final static String KEY_TEST_ID = "KEY_TEST_ID";
 
 public static void setTestId(int id) {
  TEST_ID = id;
  SPUtils.getInstance().put(KEY_TEST_ID, id);
  }
 
 public static int getTestId() {
  return TEST_ID;
  }
 
 public static void initConfigs() {
  TEST_ID = SPUtils.getInstance().getInt(KEY_TEST_ID, 0);
  }
}

随后陆续收到改进主张,有小伙伴说到 “特点署理”,并引荐了群友 DylanCai 开源库 MMKV-KTX

与此同时,受 “特点署理” 启发,自己萌发 Java 下 key、value、get、put、init 缩减为一规划。

Github:KeyValueX

V1.0

V1.0 运用 3 步曲

1.如读写 POJO,需完结 Serializable 接口

public class User implements Serializable {
 public String title;
 public String content;
}

2.像平常相同,创立项目装备管理类,如 Configs

//Configs 中不再界说一堆 KEY、VALUE 常量和 get、put、init 静态办法,
//只需一条条 KeyValue 静态变量:public class Configs {
 public final static KeyValueString accountId = new KeyValueString("accountId");
 public final static KeyValueSerializable<User> user = new KeyValueSerializable<>("user");
}

3.在页面等处经过 get( ) set( ) 办法读写 KeyValue

public class MainActivity extends AppCompatActivity {
  ...
     
 //测验耐久化写入
 Configs.user.set(u);
​
 //测验读取
 Log.d("---title", Configs.user.get().title);
 Log.d("---content", Configs.user.get().content);
}

V1.0 复盘

KeyValueX v1.0 一出,很快在群里引发热议,群友 DylanCai 说到多模块或存在 KeyName 重复问题,群友彭旭锐提议经过 “注解” 消除重复等问题。

与此同时我也发现,KeyValueX 虽然已消除 key、value、get、put、init 样板代码,但仍是有两处共同性问题:

final 修饰符和 KeyName 共同性,

—— final 在 Java 下必写,避免开发者误给 KeyValue 直接赋值

public class MainActivity extends AppCompatActivity {
  ...
   
 //正常运用
 Configs.user.set(u);
 
 //误用
 Configs.user = u;
}

那么有开发者可能说,我每次新增 KeyValue,经过 ctrl + D 复制行不就行了

public class Configs {
 public final static KeyValueString accountId = new KeyValueString("accountId");
 public final static KeyValueBoolean isAdult = new KeyValueBoolean("accountId");
}

的确这样可解决 final 共同性,但同时也会滋生 KeyName 共同性问题,也即记住改 KeyValue 变量名,忘改 KeyName,且这种疏忽编译器无法发现,唯有线上出事故专门排查时才可发现。

故综合多方面因素考虑,v2.0 采取注解规划:

V2.0

V2.0 运用 3 步曲

1.创立 KeyValueGroup 接口

@KeyValueGroup
public interface KeyValues {
 @KeyValue KeyValueInteger days();
 @KeyValue KeyValueString accountId();
 @KeyValue KeyValueSerializable<User> user();
}

2.像平常相同,创立项目装备管理类,如 Configs

//Configs 中不再界说一堆 KEY、VALUE 常量和 get、put、init 静态办法,
//只需一条 KeyValueGroup 静态变量:public class Configs {
 public final static KeyValues keyValues = KeyValueCreator.create(KeyValues.class);
}

3.在页面等处经过 get( ) set( ) 办法读写 KeyValue

public class MainActivity extends AppCompatActivity {
  ...
     
 //测验耐久化写入
 Configs.keyValues.user().set(u);
​
 //测验读取
 Log.d("---title", Configs.keyValues.user().get().title);
 Log.d("---content", Configs.keyValues.user().get().content);
}

V2.0 复盘

V2.0 经过接口 + 注解规划,一举消除 final 和 KeyName 共同性问题,

且经过无参反射完结 KeyValues 的实例化,使写代码过程中无需特意 build 生成 Impl 类,对 build 一次便需数分钟的巨型项目较友好。

KeyValueX:消除样板代码,让 Android 项目不再 KV 爆炸

依据上图可见,无参反射加载类,耗时仅次于 new,故 V2.0 规划自己还算满意,已在 Java 项目中全面运用,欢迎测验反应。

Github:KeyValueX

KeyValue-Dispatcher

期间群友 DylanCai 提出可改用动态署理完结,也即仿效 Retrofit,依据接口界说运行时动态生成办法,

如此无需声明注解,使接口界说更简练,看起来就像:

public interface KeyValues {
 KeyValueInteger days();
 KeyValueString accountId();
 KeyValueSerializable<User> user();
}

与此同时,可依据适配器模式完结个转换器,例如转换为 UnPeek-LiveData,如此即可顺带完结高频操作 —— 更新装备后告诉部分页面改写 UI。

public interface KeyValues {
  Result<Integer> days();
  Result<String> accountId();
  Result<User> user();
}
​
Configs.keyValues.days().observer(this, result -> {
  ...
});

不过动态署理有个硬伤,即类名办法名不行混淆,不然运行时难调到对应办法,

故动态署理方式终究未考虑,不过转换器规划我甚是喜欢,加之 Java 后端 Properties 启发,故萌发 Dispatcher 规划 ——

根据 MVI-Dispatcher 完结 KeyValue-Dispatcher。详细思路即经过 HashMap 内聚 KeyValue,如此只需声明 Key,而无需考虑 value、getter、setter、init:

KV-D 运用 3 步曲

1.界说 Key 列表

public class Key {
 public final static String TEST_STRING = "test_string";
 public final static String TEST_BOOLEAN = "test_boolean";
}

2.读写

//读
boolean b = GlobalConfigs.getBoolean(Key.TEST_BOOLEAN);
//写
GlobalConfigs.put(Key.TEST_STRING, value);

3.顺带可告诉 UI 改写

GlobalConfigs.output(this, keyValueEvent -> {
 switch (keyValueEvent.currentKey) {
  case Key.TEST_STRING: ... break;
  case Key.TEST_BOOLEAN: ... break;
  }
});

依托 MVI-Dispatcher 消息聚合规划,任何由装备改变引发的 UI 改写,皆从这仅有出口响应。

现在已更新至 MVI-Dispatcher 项目,感兴趣可自行查阅。

KV-D 复盘

KV-D 旨在消除学习本钱,让开发者像 SPUtils 相同运用,与此同时主动达成内存快读、消除样板代码、规避不行预期过错。

不过 KV-D 只适合 Java 项目用。如欲于 Kotlin 完结特点署理,还需根据 KeyValueX 那类规划。

于是 KeyValueX 再做升级:

1.简化注解:只需接口处声明此为 KeyValueX 接口,

2.主动分组:以 KeyValueX 接口为单位生成途径 MD5,KeyName 依据 MD5 主动分组,

3.大局内存快读:如 ViewModelProvider 运用,并供给大局内存快读。

V3.0

V3.0 运用 2 步曲

1.创立 KeyValueGroup 接口,例如

@KeyValueX
public interface Configs {
 KeyValueInteger days();
 KeyValueString accountId();
 KeyValueSerializable<User> user();
}

2.在页面等处经过 get( ) set( ) 办法读写 KeyValue

public class MainActivity extends AppCompatActivity {
 private final Configs configs = KeyValueProvider.get(Configs.class);
 
  ...
​
 //写
 configs.user().set(user);
​
 //读
 configs.user().get().title;
 configs.user().get().content;
}

已更新至 KeyValueX 项目,感兴趣可自行查阅。

Github:KeyValueX