High-performance, cross-platform key-value storage framework with static C++ linking for Android applications
—
MMKV provides advanced functionality including encryption, key expiration, backup/restore capabilities, and performance optimizations for sophisticated use cases.
MMKV supports AES encryption with custom keys up to 16 bytes for securing sensitive data.
/**
* Get the encryption key of the MMKV instance
* @return The encryption key (no more than 16 bytes), or null if not encrypted
*/
String cryptKey();
/**
* Transform plain text into encrypted text, or vice versa by passing a null encryption key.
* You can also change existing crypt key with a different cryptKey.
* @param cryptKey The new encryption key (no more than 16 bytes)
* @return True if success, otherwise False
*/
boolean reKey(String cryptKey);
/**
* Just reset the encryption key (will not encrypt or decrypt anything).
* Usually you should call this method after another process has reKey() the multi-process MMKV instance.
* @param cryptKey The new encryption key (no more than 16 bytes)
*/
void checkReSetCryptKey(String cryptKey);Usage Examples:
// Create encrypted instance
MMKV secureKv = MMKV.mmkvWithID("secure_data", MMKV.SINGLE_PROCESS_MODE, "my-secret-key");
// Check current encryption key
String currentKey = secureKv.cryptKey();
if (currentKey != null) {
Log.d("MMKV", "Instance is encrypted");
}
// Change encryption key
boolean success = secureKv.reKey("new-secret-key");
if (success) {
Log.d("MMKV", "Encryption key changed successfully");
}
// Remove encryption (convert to plain text)
boolean decrypted = secureKv.reKey(null);
// In multi-process scenario, sync key change
secureKv.checkReSetCryptKey("new-key-from-other-process");MMKV supports automatic key expiration with configurable durations to implement time-based data cleanup.
/**
* Enable auto key expiration. This is a upgrade operation, the file format will change.
* And the file won't be accessed correctly by older version (v1.2.16) of MMKV.
* NOTICE: enableCompareBeforeSet will be invalid when Expiration is on
* @param expireDurationInSecond the expire duration for all keys, 0 means no default duration
* @return True if successful, False otherwise
*/
boolean enableAutoKeyExpire(int expireDurationInSecond);
/**
* Disable auto key expiration. This is a downgrade operation.
* @return True if successful, False otherwise
*/
boolean disableAutoKeyExpire();Usage Examples:
MMKV kv = MMKV.mmkvWithID("expiring_data");
// Enable expiration with 1 hour default for all keys
boolean enabled = kv.enableAutoKeyExpire(MMKV.ExpireInHour);
if (enabled) {
// All new keys will expire in 1 hour by default
kv.encode("default_expire", "will expire in 1 hour");
// Override default expiration for specific keys
kv.encode("custom_expire", "will expire in 10 minutes", 10 * 60);
// Never expire specific keys
kv.encode("permanent", "never expires", MMKV.ExpireNever);
}
// Check expired vs non-expired keys
String[] allKeys = kv.allKeys(); // All keys including expired
String[] activeKeys = kv.allNonExpireKeys(); // Only non-expired keys
long totalCount = kv.count(); // All keys count
long activeCount = kv.countNonExpiredKeys(); // Non-expired keys count
// Disable expiration
boolean disabled = kv.disableAutoKeyExpire();MMKV provides several performance optimization features for specific use cases.
/**
* Enable data compare before set, for better performance.
* If data for key seldom changes, use it.
* When encryption or expiration is on, compare-before-set will be invalid.
*/
void enableCompareBeforeSet();
/**
* Disable data compare before set
* disabled at default
*/
void disableCompareBeforeSet();Usage Examples:
MMKV kv = MMKV.mmkvWithID("optimized_storage");
// Enable compare-before-set for better performance when data rarely changes
// Note: Invalid when encryption or expiration is enabled
kv.enableCompareBeforeSet();
// Now MMKV will compare new data with existing data before writing
kv.encode("stable_config", configData); // Only writes if data actually changed
// Disable optimization if data changes frequently
kv.disableCompareBeforeSet();MMKV provides built-in backup and restore functionality for data migration and recovery.
/**
* Backup one MMKV instance to dstDir
* @param mmapID the MMKV ID to backup
* @param dstDir the backup destination directory
* @param rootPath the customize root path of the MMKV, if null then backup from the root dir of MMKV
* @return True if backup successful, False otherwise
*/
static boolean backupOneToDirectory(String mmapID, String dstDir, String rootPath);
/**
* Restore one MMKV instance from srcDir
* @param mmapID the MMKV ID to restore
* @param srcDir the restore source directory
* @param rootPath the customize root path of the MMKV, if null then restore to the root dir of MMKV
* @return True if restore successful, False otherwise
*/
static boolean restoreOneMMKVFromDirectory(String mmapID, String srcDir, String rootPath);
/**
* Backup all MMKV instance from default root dir to dstDir
* @param dstDir the backup destination directory
* @return count of MMKV successfully backuped
*/
static long backupAllToDirectory(String dstDir);
/**
* Restore all MMKV instance from srcDir to default root dir
* @param srcDir the restore source directory
* @return count of MMKV successfully restored
*/
static long restoreAllFromDirectory(String srcDir);
/**
* Import all key-value items from another MMKV instance
* @param src The source MMKV instance to import from
* @return count of items imported
*/
long importFrom(MMKV src);Usage Examples:
// Backup specific instance
File backupDir = new File(getExternalFilesDir(null), "mmkv_backup");
backupDir.mkdirs();
boolean backupSuccess = MMKV.backupOneToDirectory(
"user_data",
backupDir.getAbsolutePath(),
null
);
if (backupSuccess) {
Log.d("MMKV", "Backup completed successfully");
}
// Backup all instances
long backedUpCount = MMKV.backupAllToDirectory(backupDir.getAbsolutePath());
Log.d("MMKV", "Backed up " + backedUpCount + " instances");
// Restore specific instance
boolean restoreSuccess = MMKV.restoreOneMMKVFromDirectory(
"user_data",
backupDir.getAbsolutePath(),
null
);
// Restore all instances
long restoredCount = MMKV.restoreAllFromDirectory(backupDir.getAbsolutePath());
Log.d("MMKV", "Restored " + restoredCount + " instances");
// Import from another MMKV instance
MMKV sourceKv = MMKV.mmkvWithID("source_data");
MMKV targetKv = MMKV.mmkvWithID("target_data");
long importedCount = targetKv.importFrom(sourceKv);
Log.d("MMKV", "Imported " + importedCount + " items");Advanced storage management capabilities for monitoring and optimizing storage usage.
/**
* Get the size of the underlying file. Align to the disk block size, typically 4K for an Android device.
* @return Total file size in bytes
*/
long totalSize();
/**
* Get the actual used size of the MMKV instance.
* This size might increase and decrease as MMKV doing insertion and full write back.
* @return Actual used size in bytes
*/
long actualSize();
/**
* The totalSize() of an MMKV instance won't reduce after deleting key-values,
* call this method after lots of deleting if you care about disk usage.
* Note that clearAll() has a similar effect.
*/
void trim();
/**
* Clear all the key-values inside the MMKV instance.
* The data file will be trimmed down to pageSize, and some sync operations will be called
* If you do not want to trim the file, use clearAllWithKeepingSpace() instead for better performance
*/
void clearAll();
/**
* Faster clearAll() implementation
* The file size is kept as previous for later use
*/
void clearAllWithKeepingSpace();
/**
* Call this method if the MMKV instance is no longer needed in the near future.
* Any subsequent call to any MMKV instances with the same ID is undefined behavior.
*/
void close();
/**
* Clear memory cache of the MMKV instance.
* You can call it on memory warning.
* Any subsequent call to the MMKV instance will trigger all key-values loading from the file again.
*/
void clearMemoryCache();Usage Examples:
MMKV kv = MMKV.mmkvWithID("large_storage");
// Monitor storage usage
long totalBytes = kv.totalSize(); // File size on disk
long usedBytes = kv.actualSize(); // Actually used space
long wastedBytes = totalBytes - usedBytes;
Log.d("MMKV", "Total: " + totalBytes + ", Used: " + usedBytes + ", Wasted: " + wastedBytes);
// Optimize storage after many deletions
if (wastedBytes > totalBytes * 0.5) { // More than 50% wasted space
kv.trim(); // Reclaim unused space
}
// Clear all data with trimming
kv.clearAll();
// Clear all data but keep file size for performance
kv.clearAllWithKeepingSpace();
// Memory management
kv.clearMemoryCache(); // Free memory cache
// Cleanup when done
kv.close(); // Close instance when no longer neededUtility methods for checking file status and managing MMKV storage files.
/**
* Check whether the MMKV file is valid or not.
* Note: Don't use this to check the existence of the instance, the result is undefined on nonexistent files.
* @param mmapID The unique ID of the MMKV instance
* @return True if the file is valid, False otherwise
*/
static boolean isFileValid(String mmapID);
/**
* Check whether the MMKV file is valid or not on customize folder.
* @param mmapID The unique ID of the MMKV instance
* @param rootPath The folder of the MMKV instance, defaults to $(FilesDir)/mmkv
* @return True if the file is valid, False otherwise
*/
static boolean isFileValid(String mmapID, String rootPath);
/**
* Remove the storage of the MMKV, including the data file & meta file (.crc)
* Note: the existing instance (if any) will be closed & destroyed
* @param mmapID The unique ID of the MMKV instance
* @return True if removal successful, False otherwise
*/
static boolean removeStorage(String mmapID);
/**
* Remove the storage of the MMKV, including the data file & meta file (.crc)
* Note: the existing instance (if any) will be closed & destroyed
* @param mmapID The unique ID of the MMKV instance
* @param rootPath The folder of the MMKV instance, defaults to $(FilesDir)/mmkv
* @return True if removal successful, False otherwise
*/
static boolean removeStorage(String mmapID, String rootPath);
/**
* Check existence of the MMKV file
* @param mmapID The unique ID of the MMKV instance
* @return True if the file exists, False otherwise
*/
static boolean checkExist(String mmapID);
/**
* Check existence of the MMKV file
* @param mmapID The unique ID of the MMKV instance
* @param rootPath The folder of the MMKV instance, defaults to $(FilesDir)/mmkv
* @return True if the file exists, False otherwise
*/
static boolean checkExist(String mmapID, String rootPath);
/**
* Get the device's memory page size
* @return Memory page size in bytes
*/
static int pageSize();
/**
* Get the version of MMKV
* @return Version string
*/
static String version();Usage Examples:
// Check if MMKV files are valid before using
if (MMKV.isFileValid("user_data")) {
MMKV kv = MMKV.mmkvWithID("user_data");
// Use normally
} else {
Log.w("MMKV", "Invalid MMKV file, may need recovery");
}
// Check file existence
if (MMKV.checkExist("temp_data")) {
// File exists, can open
} else {
// File doesn't exist, will be created on first use
}
// Remove storage files
boolean removed = MMKV.removeStorage("old_data");
if (removed) {
Log.d("MMKV", "Old storage removed successfully");
}
// System information
int pageSize = MMKV.pageSize(); // Usually 4096 on Android
String version = MMKV.version(); // e.g., "2.2.2"
Log.d("MMKV", "Page size: " + pageSize + ", Version: " + version);Direct native memory operations for advanced use cases requiring high performance.
/**
* Create an native buffer, whose underlying memory can be directly transferred to another JNI method.
* Avoiding unnecessary JNI boxing and unboxing.
* An NativeBuffer must be manually destroyed to avoid memory leak.
* @param size The size of the underlying memory
* @return NativeBuffer instance, or null if allocation failed
*/
static NativeBuffer createNativeBuffer(int size);
/**
* Destroy the native buffer. An NativeBuffer must be manually destroy to avoid memory leak.
* @param buffer The native buffer to destroy
*/
static void destroyNativeBuffer(NativeBuffer buffer);
/**
* Write the value of the key to the native buffer.
* @param key The key to read
* @param buffer The native buffer to write to
* @return The size written. Return -1 on any error
*/
int writeValueToNativeBuffer(String key, NativeBuffer buffer);Usage Examples:
// Create native buffer for high-performance operations
NativeBuffer buffer = MMKV.createNativeBuffer(1024);
if (buffer != null) {
try {
MMKV kv = MMKV.mmkvWithID("high_perf");
// Write value directly to native buffer
int bytesWritten = kv.writeValueToNativeBuffer("large_data", buffer);
if (bytesWritten > 0) {
// Pass buffer to other JNI methods for processing
// processNativeBuffer(buffer.pointer, buffer.size);
}
} finally {
// Always destroy buffer to prevent memory leaks
MMKV.destroyNativeBuffer(buffer);
}
}/**
* A native memory wrapper, whose underlying memory can be passed to another JNI method directly.
* Avoiding unnecessary JNI boxing and unboxing.
* Must be destroy manually.
*/
class NativeBuffer {
public long pointer; // Native memory pointer
public int size; // Buffer size
NativeBuffer(long ptr, int length);
}Install with Tessl CLI
npx tessl i tessl/maven-com-tencent--mmkv-static