FastKV

Project Url: BillyWei01/FastKV
Introduction: FastKV is an efficient and reliable key-value storage component.
More: Author   ReportBugs   OfficialWebsite   
Tags:

Maven Central | English | 架构设计

1. 概述

FastKV 是用 Java 编写的高效可靠的 key-value 存储库,专为 Android 平台优化。

核心特性

1. 高性能读写

  • 二进制编码:采用紧凑的二进制格式,相比 XML 等文本编码体积更小
  • 增量更新:记录 key-value 的精确偏移量,支持原地更新,避免全量重写
  • mmap 内存映射:默认使用 mmap 技术,写入数据直接映射到内存
  • 垃圾回收:自动清理无效数据,保持存储空间紧凑

2. 多种写入模式

  • NON_BLOCKING:非阻塞模式,通过 mmap 直接写入内存,性能最高
  • ASYNC_BLOCKING:异步阻塞模式,后台线程写入磁盘,类似 SharedPreferences.apply()
  • SYNC_BLOCKING:同步阻塞模式,立即写入磁盘,类似 SharedPreferences.commit()

3. 丰富的数据类型支持

  • 基础类型:boolean, int, float, long, double, String
  • 字节数组:byte[],支持二进制数据存储
  • 字符串集合:Set,完全兼容 SharedPreferences
  • 自定义对象:通过 FastEncoder 接口支持任意对象序列化

4. 数据安全保障

  • 双文件备份:A/B 文件互为备份,确保数据不丢失
  • 校验和保护:每次读取都验证数据完整性
  • 原子操作:写入操作具有原子性,避免数据损坏
  • 自动降级:mmap 失败时自动切换到阻塞模式

5. 数据加密支持

  • 可插拔加密:支持注入自定义加密实现
  • 透明加解密:加密在数据写入前执行,解密在数据解析时执行
  • 加密迁移:支持从明文到密文的平滑迁移
  • 性能优化:缓存解密后的数据,不影响读取性能

6. 开发友好

  • 兼容性好:实现 SharedPreferences 接口,便于迁移
  • 迁移工具:提供 adapt()方法自动迁移 SharedPreferences 数据
  • 丰富 API:支持批量操作、监听器等
  • 类型安全:编译时类型检查,避免运行时类型错误

7. 稳定可靠

  • 容错机制:基本的错误检测和自动恢复
  • 向前兼容:新版本可读取旧版本数据
  • 异常处理:基本的异常处理和日志记录

8. 轻量高效

  • 体积小:纯 Java 实现,编译后仅数十 KB
  • 内存友好:减少不必要的对象创建
  • 启动快:异步加载,支持多文件并发加载

2. 使用方法

2.1 导入

dependencies {
    implementation 'io.github.billywei01:fastkv:3.0.1'
}

备注:
在 2.x 版本,FastKV 支持多进程存储,但 3.x 版本开始不再支持多进程。
如需多进程存储,请使用MPFastKV

2.2 初始化

// 可选:设置全局配置
FastKVConfig.setLogger(FastKVLogger)
FastKVConfig.setExecutor(Dispatchers.IO.asExecutor())

初始化可以按需设置日志接口和 Executor:

  • 如果不传入 Executor,FastKV 会自己构建一个 CachedThreadPool
  • 如果传入用户自己的 Executor,需要确保 Executor 的并发调度能力

2.3 基本用法

// 使用 Context 构造(推荐)
FastKV kv = new FastKV.Builder(context, "user_data").build();

// 或使用自定义路径
FastKV kv = new FastKV.Builder(path, "user_data").build();

// 基本读写操作
if (!kv.getBoolean("first_launch")) {
    kv.putBoolean("first_launch", true);
}

int count = kv.getInt("launch_count");
kv.putInt("launch_count", count + 1);

// 支持链式调用
kv.putString("user_name", "张三")
  .putInt("user_age", 25)
  .putFloat("user_score", 89.5f);

2.4 可选配置

FastKV kv = new FastKV.Builder(context, "secure_data")
    .encoder(new FastEncoder[]{CustomObjectEncoder.INSTANCE})  // 自定义编码器
    .cipher(new AESCipher())                                   // 数据加密
    .blocking()                                                // 同步阻塞模式
    .build();

2.5 存储自定义对象

// 1. 实现 FastEncoder 接口
public class UserEncoder implements FastEncoder<User> {
    @Override
    public String tag() {
        return "User";
    }

    @Override
    public byte[] encode(User user) {
        // 序列化逻辑
        return userToBytes(user);
    }

    @Override
    public User decode(byte[] bytes, int offset, int length) {
        // 反序列化逻辑
        return bytesToUser(bytes, offset, length);
    }
}

// 2. 注册编码器并使用
FastEncoder<?>[] encoders = {new UserEncoder()};
FastKV kv = new FastKV.Builder(context, "user_data")
    .encoder(encoders)
    .build();

// 3. 存储和读取对象
User user = new User("张三", 25);
kv.putObject("current_user", user, new UserEncoder());
User savedUser = kv.getObject("current_user");

推荐使用Packable框架进行对象序列化。

2.6 数据加密

// 实现 FastCipher 接口
public class AESCipher implements FastCipher {
    @Override
    public byte[] encrypt(byte[] src) {
        // 加密实现
        return encryptWithAES(src);
    }

    @Override
    public byte[] decrypt(byte[] dst) {
        // 解密实现
        return decryptWithAES(dst);
    }

    // 其他加密方法...
}

// 使用加密
FastKV kv = new FastKV.Builder(context, "secure_data")
    .cipher(new AESCipher())
    .build();

2.7 批量操作

// 批量写入
Map<String, Object> data = new HashMap<>();
data.put("name", "张三");
data.put("age", 25);
data.put("score", 89.5f);
data.put("active", true);

kv.putAll(data);

// 批量读取
Map<String, Object> allData = kv.getAll();

// 事务控制(阻塞模式)
kv.disableAutoCommit();
kv.putString("key1", "value1");
kv.putString("key2", "value2");
kv.commit(); // 一次性提交所有更改

2.8 迁移 SharedPreferences

public class SpCase {
    public static final String NAME = "common_store";

    // 替换原有的 SharedPreferences 获取方式
    // public static final SharedPreferences preferences = context.getSharedPreferences(NAME, Context.MODE_PRIVATE);

    // 使用 FastKV 并自动迁移数据
    public static final SharedPreferences preferences = FastKV.adapt(context, NAME);
}

2.9 监听数据变化

kv.registerOnSharedPreferenceChangeListener(new SharedPreferences.OnSharedPreferenceChangeListener() {
    @Override
    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
        // 处理数据变化
        System.out.println("Key changed: " + key);
    }
});

2.10 Kotlin 委托属性

Kotlin 是兼容 Java 的,所以 Kotlin 下也可以直接用 FastKV 或者 SharedPreferences 的 API。
此外,Kotlin 还提供了“委托属性”这一语法糖,可以用于改进 key-value API 访问。
可参考:KVData
具体细节可参考: 一种好用的 KV 存储封装方案

2.11 注意事项

  1. 路径和名称一致性:不同版本之间不要改变路径和名字,否则会打开不同的文件
  2. 加密器一致性:如果使用了 Cipher,不要更换,否则无法解析数据(从无加密到加密是可以的)
  3. 类型一致性:同一个 key 对应的 value 类型应保持一致

3. 性能测试

测试环境

  • 测试数据:600+个真实 key-value 数据(经过随机混淆)
  • 测试设备:华为 P30 Pro
  • 测试方法:正态分布输入序列,多次测试取平均值

测试结果

写入性能(毫秒)

数据量 25 50 100 200 400 600
SP-commit 114 172 411 666 2556 5344
DataStore 231 625 1717 4421 7629 13639
SQLiteKV 192 382 1025 1565 4279 5034
SP-apply 3 9 35 118 344 516
MMKV 4 8 5 8 10 9
FastKV 3 6 4 6 8 10

读取性能(毫秒)

数据量 25 50 100 200 400 600
SP-commit 1 3 2 1 2 3
DataStore 57 76 115 117 170 216
SQLiteKV 96 161 265 417 767 1038
SP-apply 0 1 0 1 3 3
MMKV 0 1 1 5 8 11
FastKV 0 1 1 3 3 1

性能优势

  • 写入速度:与 MMKV 相当,比 SharedPreferences 显著更快
  • 读取速度:与 SharedPreferences 相当,比 DataStore 更快
  • 启动速度:异步加载,不阻塞应用启动

4. 架构设计

如果对 FastKV 的实现原理感兴趣,可参考ARCHITECTURE.md

5. 相关链接

License

See the LICENSE file for license rights and limitations.

Apps
About Me
GitHub: Trinea
Facebook: Dev Tools