MMKV is an efficient, small, easy-to-use mobile key-value storage framework used in the WeChat application.
—
Comprehensive data management including backup/restore operations, file validation, storage cleanup, and performance optimization. MMKV provides extensive tools for maintaining data integrity and optimizing storage usage.
Manage and query keys within MMKV instances.
/**
* Check whether or not MMKV contains the key.
* @param key The key of the value
* @return true if key exists, false otherwise
*/
public boolean containsKey(String key);
/**
* Get all keys.
* @return Array of all keys, or null if empty
*/
public String[] allKeys();
/**
* Get all non-expired keys. Note that this call has costs.
* @return Array of all non-expired keys, or null if empty
*/
public String[] allNonExpireKeys();
/**
* Get the total count of all keys.
* @return The total count of all keys
*/
public long count();
/**
* Get the total count of all non-expired keys. Note that this call has costs.
* @return The total count of all non-expired keys
*/
public long countNonExpiredKeys();Usage Example:
MMKV kv = MMKV.defaultMMKV();
// Add some data
kv.encode("user_name", "Alice");
kv.encode("user_age", 25);
kv.encode("temp_data", "temporary", MMKV.ExpireInMinute);
// Check key existence
if (kv.containsKey("user_name")) {
String name = kv.decodeString("user_name", "");
Log.d("MMKV", "User name: " + name);
}
// Get all keys
String[] allKeys = kv.allKeys();
if (allKeys != null) {
Log.d("MMKV", "Total keys: " + allKeys.length);
for (String key : allKeys) {
Log.d("MMKV", "Key: " + key);
}
}
// Get key counts
long totalCount = kv.count();
long nonExpiredCount = kv.countNonExpiredKeys();
Log.d("MMKV", "Total: " + totalCount + ", Non-expired: " + nonExpiredCount);
// Get only non-expired keys
String[] activeKeys = kv.allNonExpireKeys();
Log.d("MMKV", "Active keys: " + (activeKeys != null ? activeKeys.length : 0));Get detailed information about stored values and their memory usage.
/**
* Get the actual size consumption of the key's value.
* Note: might be a little bigger than value's length.
* @param key The key of the value
* @return Size in bytes of the stored value
*/
public int getValueSize(String key);
/**
* Get the actual size of the key's value. String's length or byte[]'s length, etc.
* @param key The key of the value
* @return Actual size of the value data
*/
public int getValueActualSize(String key);
/**
* 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
*/
public 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
*/
public long actualSize();Usage Example:
// Store various types of data
kv.encode("short_text", "Hello");
kv.encode("long_text", "This is a much longer string that will take more space");
kv.encode("large_data", new byte[10240]); // 10KB byte array
// Analyze storage usage
String[] keys = kv.allKeys();
if (keys != null) {
for (String key : keys) {
int storageSize = kv.getValueSize(key);
int actualSize = kv.getValueActualSize(key);
Log.d("MMKV", String.format("Key: %s, Storage: %d bytes, Actual: %d bytes",
key, storageSize, actualSize));
}
}
// Get overall file statistics
long totalFileSize = kv.totalSize();
long usedSize = kv.actualSize();
double utilizationRatio = (double) usedSize / totalFileSize;
Log.d("MMKV", String.format("File size: %d KB, Used: %d KB, Utilization: %.1f%%",
totalFileSize / 1024, usedSize / 1024, utilizationRatio * 100));Remove individual keys or clear entire MMKV instances.
/**
* Remove a single key-value pair.
* @param key The key to remove
*/
public void removeValueForKey(String key);
/**
* Batch remove some keys from the MMKV instance.
* @param arrKeys The keys to be removed
*/
public void removeValuesForKeys(String[] arrKeys);
/**
* 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.
*/
public void clearAll();
/**
* Faster clearAll() implementation.
* The file size is kept as previous for later use.
*/
public void clearAllWithKeepingSpace();Usage Example:
// Remove single key
kv.removeValueForKey("temp_data");
// Remove multiple keys at once
String[] keysToRemove = {"old_cache", "expired_token", "temp_config"};
kv.removeValuesForKeys(keysToRemove);
// Clear all data with file trimming (slower but saves disk space)
kv.clearAll();
// Clear all data keeping file size (faster, good for temporary clearing)
MMKV tempKv = MMKV.mmkvWithID("temp_storage");
tempKv.clearAllWithKeepingSpace(); // Faster for frequent clear operations
// Example: Cleanup old data based on patterns
String[] allKeys = kv.allKeys();
if (allKeys != null) {
List<String> expiredKeys = new ArrayList<>();
for (String key : allKeys) {
if (key.startsWith("cache_") && isExpired(key)) {
expiredKeys.add(key);
}
}
if (!expiredKeys.isEmpty()) {
kv.removeValuesForKeys(expiredKeys.toArray(new String[0]));
Log.d("MMKV", "Removed " + expiredKeys.size() + " expired cache keys");
}
}Optimize file usage and perform maintenance operations.
/**
* 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.
*/
public void trim();
/**
* Save all mmap memory to file synchronously.
* You don't need to call this, really, I mean it.
* Unless you worry about the device running out of battery.
*/
public void sync();
/**
* Save all mmap memory to file asynchronously.
* No need to call this unless you worry about the device running out of battery.
*/
public void async();
/**
* 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.
*/
public void clearMemoryCache();Usage Example:
// Trim file after bulk deletions
long sizeBefore = kv.totalSize();
// ... perform many deletions ...
kv.trim();
long sizeAfter = kv.totalSize();
Log.d("MMKV", "File size reduced by " + (sizeBefore - sizeAfter) + " bytes");
// Force synchronization before critical operations
kv.sync(); // Synchronous - blocks until complete
// Or use asynchronous version
kv.async(); // Non-blocking
// Handle memory pressure
@Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
switch (level) {
case TRIM_MEMORY_MODERATE:
case TRIM_MEMORY_RUNNING_MODERATE:
// Clear non-critical MMKV caches
cacheMmkv.clearMemoryCache();
break;
case TRIM_MEMORY_COMPLETE:
case TRIM_MEMORY_RUNNING_CRITICAL:
// Clear all MMKV memory caches
kv.clearMemoryCache();
cacheMmkv.clearMemoryCache();
break;
}
}Validate MMKV files and check data integrity.
/**
* 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 file is valid, false otherwise
*/
public 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 file is valid, false otherwise
*/
public static boolean isFileValid(String mmapID, String rootPath);
/**
* Check existence of the MMKV file.
* @param mmapID The unique ID of the MMKV instance
* @return true if file exists, false otherwise
*/
public 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 file exists, false otherwise
*/
public static boolean checkExist(String mmapID, String rootPath);Usage Example:
// Check if MMKV files exist and are valid
String[] instanceIds = {"user_data", "cache_data", "settings"};
for (String instanceId : instanceIds) {
boolean exists = MMKV.checkExist(instanceId);
boolean isValid = exists && MMKV.isFileValid(instanceId);
Log.d("MMKV", String.format("Instance %s: exists=%b, valid=%b",
instanceId, exists, isValid));
if (exists && !isValid) {
Log.w("MMKV", "Corrupted MMKV file detected: " + instanceId);
// Handle corruption - maybe restore from backup or recreate
handleCorruptedFile(instanceId);
}
}
private void handleCorruptedFile(String instanceId) {
// Remove corrupted file
boolean removed = MMKV.removeStorage(instanceId);
if (removed) {
Log.d("MMKV", "Removed corrupted file: " + instanceId);
// Recreate with default values
MMKV newInstance = MMKV.mmkvWithID(instanceId);
initializeDefaultValues(newInstance);
}
}Permanently remove MMKV storage files.
/**
* 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 was successful, false otherwise
*/
public 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 was successful, false otherwise
*/
public static boolean removeStorage(String mmapID, String rootPath);Usage Example:
// Clean up temporary storage
boolean tempRemoved = MMKV.removeStorage("temp_cache");
if (tempRemoved) {
Log.d("MMKV", "Temporary cache storage removed");
}
// Remove storage with custom path
File customDir = new File(getExternalFilesDir(null), "custom_mmkv");
boolean customRemoved = MMKV.removeStorage("custom_data", customDir.getAbsolutePath());
// Bulk cleanup of old instances
String[] oldInstances = {"old_cache_v1", "deprecated_settings", "temp_data_2023"};
int removedCount = 0;
for (String instanceId : oldInstances) {
if (MMKV.removeStorage(instanceId)) {
removedCount++;
}
}
Log.d("MMKV", "Removed " + removedCount + " old storage instances");Comprehensive backup and restore functionality for data protection and migration.
/**
* 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 was successful, false otherwise
*/
public 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 was successful, false otherwise
*/
public static boolean restoreOneMMKVFromDirectory(String mmapID, String srcDir, String rootPath);
/**
* Backup all MMKV instances from default root dir to dstDir.
* @param dstDir The backup destination directory
* @return Count of MMKV instances successfully backed up
*/
public static long backupAllToDirectory(String dstDir);
/**
* Restore all MMKV instances from srcDir to default root dir.
* @param srcDir The restore source directory
* @return Count of MMKV instances successfully restored
*/
public static long restoreAllFromDirectory(String srcDir);Usage Example:
// Backup individual instance
File backupDir = new File(getExternalFilesDir(null), "mmkv_backup");
if (!backupDir.exists()) {
backupDir.mkdirs();
}
boolean backupSuccess = MMKV.backupOneToDirectory(
"user_data",
backupDir.getAbsolutePath(),
null
);
if (backupSuccess) {
Log.d("MMKV", "User data backed up successfully");
} else {
Log.e("MMKV", "Failed to backup user data");
}
// Restore individual instance
File restoreDir = new File(getExternalFilesDir(null), "mmkv_backup");
boolean restoreSuccess = MMKV.restoreOneMMKVFromDirectory(
"user_data",
restoreDir.getAbsolutePath(),
null
);
// Backup all instances
long backedUpCount = MMKV.backupAllToDirectory(backupDir.getAbsolutePath());
Log.d("MMKV", "Backed up " + backedUpCount + " MMKV instances");
// Restore all instances
long restoredCount = MMKV.restoreAllFromDirectory(restoreDir.getAbsolutePath());
Log.d("MMKV", "Restored " + restoredCount + " MMKV instances");
// Automated backup strategy
private void performRegularBackup() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US);
String timestamp = sdf.format(new Date());
File backupDir = new File(getExternalFilesDir(null), "mmkv_backup_" + timestamp);
backupDir.mkdirs();
long backupCount = MMKV.backupAllToDirectory(backupDir.getAbsolutePath());
if (backupCount > 0) {
Log.d("MMKV", "Backup completed: " + backupCount + " instances");
// Keep only last 5 backups
cleanupOldBackups();
}
}Import data from other MMKV instances or SharedPreferences.
/**
* Import all key-value items from src MMKV instance.
* @param src Source MMKV instance to import from
* @return Count of items imported
*/
public long importFrom(MMKV src);
/**
* Atomically migrate all key-values from an existent SharedPreferences to the MMKV instance.
* @param preferences The SharedPreferences to import from
* @return The total count of key-values imported
*/
public int importFromSharedPreferences(SharedPreferences preferences);Usage Example:
// Migrate from SharedPreferences to MMKV
SharedPreferences oldPrefs = getSharedPreferences("old_settings", MODE_PRIVATE);
MMKV newKv = MMKV.mmkvWithID("migrated_settings");
int migratedCount = newKv.importFromSharedPreferences(oldPrefs);
Log.d("MMKV", "Migrated " + migratedCount + " settings from SharedPreferences");
// Merge data from multiple MMKV instances
MMKV masterKv = MMKV.mmkvWithID("master_data");
MMKV tempKv1 = MMKV.mmkvWithID("temp_data_1");
MMKV tempKv2 = MMKV.mmkvWithID("temp_data_2");
long imported1 = masterKv.importFrom(tempKv1);
long imported2 = masterKv.importFrom(tempKv2);
Log.d("MMKV", "Imported " + (imported1 + imported2) + " items to master instance");
// Clean up temporary instances after import
MMKV.removeStorage("temp_data_1");
MMKV.removeStorage("temp_data_2");Properly manage MMKV instance lifecycle and resources.
/**
* 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.
*/
public void close();Usage Example:
public class DataManager {
private MMKV cacheKv;
private MMKV userKv;
public void initialize() {
cacheKv = MMKV.mmkvWithID("app_cache");
userKv = MMKV.mmkvWithID("user_data");
}
public void cleanup() {
// Close instances when no longer needed
if (cacheKv != null) {
cacheKv.close();
cacheKv = null;
}
if (userKv != null) {
userKv.close();
userKv = null;
}
}
// Call during app lifecycle events
@Override
protected void onDestroy() {
super.onDestroy();
cleanup();
}
}Install with Tessl CLI
npx tessl i tessl/maven-com-tencent--mmkv-shared