CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-com-tencent--mmkv

High-performance mobile key-value storage framework with memory mapping, encryption, and multi-process support for Android applications.

Pending
Overview
Eval results
Files

data-management.mddocs/

Data Management

Advanced data management operations including key inspection, file operations, backup/restore capabilities, and performance optimization methods.

Capabilities

Key Inspection

Methods for inspecting and analyzing stored keys and their properties.

/**
 * Check whether MMKV contains the key.
 * @param key The key to check
 * @return True if key exists, false otherwise
 */
public boolean containsKey(String key);

/**
 * Get all keys in the MMKV instance.
 * @return Array of all keys, or null if no keys exist
 */
public String[] allKeys();

/**
 * Get all non-expired keys in the MMKV instance.
 * Note: This call has performance costs.
 * @return Array of non-expired keys, or null if no keys exist
 */
public String[] allNonExpireKeys();

/**
 * Get the total count of all keys.
 * @return The total number of keys
 */
public long count();

/**
 * Get the total count of all non-expired keys.
 * Note: This call has performance costs.
 * @return The total number of non-expired keys
 */
public long countNonExpiredKeys();

Usage Example:

MMKV kv = MMKV.defaultMMKV();

// Add some test data
kv.encode("user_id", 123);
kv.encode("username", "john_doe");
kv.encode("is_premium", true);
kv.encode("temp_data", "temporary", MMKV.ExpireInMinute);

// Check if specific keys exist
boolean hasUserId = kv.containsKey("user_id");        // true
boolean hasEmail = kv.containsKey("email");           // false

// 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 count of keys
long totalCount = kv.count();                         // 4
long nonExpiredCount = kv.countNonExpiredKeys();      // 3 (after temp_data expires)

Log.d("MMKV", String.format("Total: %d, Non-expired: %d", totalCount, nonExpiredCount));

// Get only non-expired keys (more expensive operation)
String[] activeKeys = kv.allNonExpireKeys();

Value Size Analysis

Analyze the size and memory usage of stored values.

/**
 * Get the actual size consumption of the key's value.
 * Note: Might be slightly larger than value's length due to metadata.
 * @param key The key of the value
 * @return The size in bytes
 */
public int getValueSize(String key);

/**
 * Get the actual size of the key's value.
 * Returns string length or byte array length, etc.
 * @param key The key of the value
 * @return The actual value size in bytes
 */
public int getValueActualSize(String key);

/**
 * Get the size of the underlying file.
 * Aligned to disk block size, typically 4K for Android devices.
 * @return The 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 does insertion and full write back.
 * @return The actual used size in bytes
 */
public long actualSize();

Usage Example:

MMKV kv = MMKV.defaultMMKV();

// Store different types of data
kv.encode("short_string", "Hello");
kv.encode("long_string", "This is a much longer string that will take more space");
kv.encode("large_number", 1234567890L);
byte[] imageData = new byte[1024 * 100]; // 100KB of data
kv.encode("image_data", imageData);

// Analyze individual value sizes
int shortStringSize = kv.getValueSize("short_string");          // ~5 + metadata
int shortStringActual = kv.getValueActualSize("short_string");  // 5
int longStringSize = kv.getValueSize("long_string");
int imageDataSize = kv.getValueSize("image_data");              // ~100KB + metadata

Log.d("MMKV", String.format("Short string: %d bytes (actual: %d)", 
                            shortStringSize, shortStringActual));
Log.d("MMKV", String.format("Long string: %d bytes", longStringSize));
Log.d("MMKV", String.format("Image data: %d bytes", imageDataSize));

// Analyze overall file sizes
long totalFileSize = kv.totalSize();    // File size on disk (aligned to 4K blocks)
long actualUsedSize = kv.actualSize();  // Actual data size used

Log.d("MMKV", String.format("Total file size: %d bytes (%.2f KB)", 
                            totalFileSize, totalFileSize / 1024.0));
Log.d("MMKV", String.format("Actual used size: %d bytes (%.2f KB)", 
                            actualUsedSize, actualUsedSize / 1024.0));
Log.d("MMKV", String.format("Efficiency: %.1f%%", 
                            (actualUsedSize * 100.0) / totalFileSize));

Data Removal

Remove individual keys, multiple keys, or clear all data.

/**
 * Remove the value for a specific key.
 * @param key The key to remove
 */
public void removeValueForKey(String key);

/**
 * Batch remove multiple keys from the MMKV instance.
 * @param arrKeys Array of keys to be removed
 */
public void removeValuesForKeys(String[] arrKeys);

/**
 * Clear all key-values inside the MMKV instance.
 * The data file will be trimmed down to pageSize and sync operations called.
 * For better performance without file trimming, use clearAllWithKeepingSpace().
 */
public void clearAll();

/**
 * Faster clearAll() implementation that keeps the file size.
 * The file size is kept as previous for later use.
 */
public void clearAllWithKeepingSpace();

Usage Example:

MMKV kv = MMKV.defaultMMKV();

// Add test data
kv.encode("keep_this", "important data");
kv.encode("temp1", "temporary data 1");
kv.encode("temp2", "temporary data 2");
kv.encode("temp3", "temporary data 3");
kv.encode("delete_this", "data to delete");

// Remove single key
kv.removeValueForKey("delete_this");

// Remove multiple keys at once (more efficient than individual removes)
String[] keysToRemove = {"temp1", "temp2", "temp3"};
kv.removeValuesForKeys(keysToRemove);

// Check what's left
String[] remainingKeys = kv.allKeys();
Log.d("MMKV", "Remaining keys: " + Arrays.toString(remainingKeys)); // Should show "keep_this"

// Clear all data (with file trimming for space reclamation)
long sizeBefore = kv.totalSize();
kv.clearAll();
long sizeAfter = kv.totalSize();
Log.d("MMKV", String.format("Size before clear: %d, after: %d", sizeBefore, sizeAfter));

// Alternative: clear all but keep file size for performance
kv.encode("test", "data");
kv.clearAllWithKeepingSpace(); // Faster, but doesn't reclaim disk space

File Maintenance

Operations for maintaining and optimizing MMKV file storage.

/**
 * Reduce file size after lots of deletions.
 * 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: clearAll() has a similar effect.
 */
public void trim();

/**
 * Save all mmap memory to file synchronously.
 * You don't need to call this normally - MMKV handles persistence automatically.
 * Use only if you worry about device running out of battery.
 */
public void sync();

/**
 * Save all mmap memory to file asynchronously.
 * No need to call this unless you worry about losing battery power.
 */
public void async();

/**
 * Clear memory cache of the MMKV instance.
 * Call this on memory warning to free up RAM.
 * Any subsequent call will trigger key-values loading from file again.
 */
public void clearMemoryCache();

/**
 * Call this method if the MMKV instance is no longer needed.
 * Any subsequent call to MMKV instances with the same ID is undefined behavior.
 */
public void close();

Usage Example:

public class MMKVMaintenanceExample {
    
    private MMKV kv;
    
    public void demonstrateFileMaintenance() {
        kv = MMKV.mmkvWithID("maintenance_example");
        
        // Add lots of data
        for (int i = 0; i < 10000; i++) {
            kv.encode("key_" + i, "value_" + i);
        }
        
        long sizeBefore = kv.totalSize();
        Log.d("MMKV", "Size before deletions: " + sizeBefore);
        
        // Delete most of the data
        for (int i = 0; i < 9000; i++) {
            kv.removeValueForKey("key_" + i);
        }
        
        long sizeAfterDeletion = kv.totalSize();
        Log.d("MMKV", "Size after deletions: " + sizeAfterDeletion); // Still large
        
        // Trim file to reclaim space
        kv.trim();
        
        long sizeAfterTrim = kv.totalSize();
        Log.d("MMKV", "Size after trim: " + sizeAfterTrim); // Much smaller
        
        // Force synchronous save to disk
        kv.sync();
        
        // Or use asynchronous save for better performance
        kv.async();
    }
    
    public void handleMemoryPressure() {
        // Clear memory cache to free RAM
        kv.clearMemoryCache();
        Log.d("MMKV", "Memory cache cleared due to memory pressure");
    }
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        // Close MMKV instance when no longer needed
        if (kv != null) {
            kv.close();
            kv = null;
        }
    }
}

Data Import and Export

Import data from other sources and export for backup purposes.

/**
 * Import all key-value items from another MMKV instance.
 * @param src The source MMKV instance to import from
 * @return Count of items imported
 */
public long importFrom(MMKV src);

/**
 * Atomically migrate all key-values from an existing SharedPreferences.
 * @param preferences The SharedPreferences to import from
 * @return The total count of key-values imported
 */
public int importFromSharedPreferences(SharedPreferences preferences);

Usage Example:

public class MMKVImportExportExample {
    
    /**
     * Migrate from SharedPreferences to MMKV.
     */
    public void migrateFromSharedPreferences(Context context) {
        // Get existing SharedPreferences
        SharedPreferences oldPrefs = context.getSharedPreferences("user_prefs", Context.MODE_PRIVATE);
        
        // Create new MMKV instance
        MMKV newKv = MMKV.mmkvWithID("user_prefs");
        
        // Import all data from SharedPreferences
        int importedCount = newKv.importFromSharedPreferences(oldPrefs);
        
        Log.d("MMKV", "Imported " + importedCount + " items from SharedPreferences");
        
        // Verify the migration
        if (importedCount > 0) {
            // Clear old SharedPreferences after successful migration
            oldPrefs.edit().clear().apply();
            Log.d("MMKV", "Successfully migrated to MMKV");
        }
    }
    
    /**
     * Copy data between MMKV instances.
     */
    public void copyDataBetweenInstances() {
        // Source instance with data
        MMKV sourceKv = MMKV.mmkvWithID("source_data");
        sourceKv.encode("user_id", 123);
        sourceKv.encode("username", "john");
        sourceKv.encode("settings", "dark_mode=true");
        
        // Destination instance
        MMKV destKv = MMKV.mmkvWithID("backup_data");
        
        // Import all data from source to destination
        long importedCount = destKv.importFrom(sourceKv);
        
        Log.d("MMKV", "Imported " + importedCount + " items to backup");
        
        // Verify the copy
        String username = destKv.decodeString("username"); // "john"
        int userId = destKv.decodeInt("user_id");           // 123
        
        Log.d("MMKV", String.format("Verified backup: user=%s, id=%d", username, userId));
    }
    
    /**
     * Create incremental backup.
     */
    public void createIncrementalBackup() {
        MMKV mainKv = MMKV.defaultMMKV();
        MMKV backupKv = MMKV.mmkvWithID("incremental_backup");
        
        // Get timestamp of last backup
        long lastBackupTime = backupKv.decodeLong("last_backup_time", 0);
        
        // Import all current data (MMKV handles duplicates efficiently)
        long importedCount = backupKv.importFrom(mainKv);
        
        // Update backup timestamp
        backupKv.encode("last_backup_time", System.currentTimeMillis());
        
        Log.d("MMKV", String.format("Incremental backup: %d items, last backup: %d", 
                                   importedCount, lastBackupTime));
    }
}

Backup and Restore Operations

File-level backup and restore operations for data protection.

/**
 * Backup one MMKV instance to destination directory.
 * @param mmapID The MMKV ID to backup
 * @param dstDir The backup destination directory
 * @param rootPath The customize root path of the MMKV, null for default root
 * @return True if backup successful
 */
public static boolean backupOneToDirectory(String mmapID, String dstDir, String rootPath);

/**
 * Restore one MMKV instance from source directory.
 * @param mmapID The MMKV ID to restore
 * @param srcDir The restore source directory
 * @param rootPath The customize root path of the MMKV, null for default root
 * @return True if restore successful
 */
public static boolean restoreOneMMKVFromDirectory(String mmapID, String srcDir, String rootPath);

/**
 * Backup all MMKV instances from default root dir to destination directory.
 * @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 source directory 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:

public class MMKVBackupRestoreExample {
    
    /**
     * Create backup of specific MMKV instances.
     */
    public void backupSpecificInstances(Context context) {
        // Create backup directory
        File backupDir = new File(context.getExternalFilesDir(null), "mmkv_backup");
        if (!backupDir.exists()) {
            backupDir.mkdirs();
        }
        
        String backupPath = backupDir.getAbsolutePath();
        
        // Backup specific instances
        boolean userBackup = MMKV.backupOneToDirectory("user_data", backupPath, null);
        boolean settingsBackup = MMKV.backupOneToDirectory("app_settings", backupPath, null);
        
        Log.d("MMKV", String.format("Backup results - User: %b, Settings: %b", 
                                   userBackup, settingsBackup));
        
        if (userBackup && settingsBackup) {
            // Store backup metadata
            MMKV backupMeta = MMKV.mmkvWithID("backup_metadata");
            backupMeta.encode("last_backup_time", System.currentTimeMillis());
            backupMeta.encode("backup_path", backupPath);
            backupMeta.encode("backup_count", 2);
        }
    }
    
    /**
     * Backup all MMKV instances.
     */
    public void backupAllInstances(Context context) {
        File backupDir = new File(context.getExternalFilesDir(null), "mmkv_full_backup");
        backupDir.mkdirs();
        
        // Backup all instances
        long backedUpCount = MMKV.backupAllToDirectory(backupDir.getAbsolutePath());
        
        Log.d("MMKV", "Backed up " + backedUpCount + " MMKV instances");
        
        // Create backup manifest
        MMKV manifest = MMKV.mmkvWithID("backup_manifest");
        manifest.encode("backup_timestamp", System.currentTimeMillis());
        manifest.encode("backup_count", backedUpCount);
        manifest.encode("backup_type", "full");
    }
    
    /**
     * Restore from backup.
     */
    public void restoreFromBackup(String backupPath) {
        try {
            // Restore specific instances
            boolean userRestored = MMKV.restoreOneMMKVFromDirectory("user_data", backupPath, null);
            boolean settingsRestored = MMKV.restoreOneMMKVFromDirectory("app_settings", backupPath, null);
            
            if (userRestored && settingsRestored) {
                Log.d("MMKV", "Successfully restored specific instances");
            }
            
            // Or restore all instances
            long restoredCount = MMKV.restoreAllFromDirectory(backupPath);
            Log.d("MMKV", "Restored " + restoredCount + " instances from backup");
            
        } catch (Exception e) {
            Log.e("MMKV", "Failed to restore from backup", e);
        }
    }
    
    /**
     * Automated backup with rotation.
     */
    public void automatedBackupWithRotation(Context context) {
        File backupRoot = new File(context.getExternalFilesDir(null), "mmkv_backups");
        backupRoot.mkdirs();
        
        // Create timestamped backup directory
        String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US)
                                .format(new Date());
        File currentBackup = new File(backupRoot, "backup_" + timestamp);
        currentBackup.mkdirs();
        
        // Perform backup
        long backedUpCount = MMKV.backupAllToDirectory(currentBackup.getAbsolutePath());
        
        if (backedUpCount > 0) {
            // Keep only last 5 backups
            File[] backups = backupRoot.listFiles((dir, name) -> name.startsWith("backup_"));
            if (backups != null && backups.length > 5) {
                Arrays.sort(backups, (a, b) -> a.getName().compareTo(b.getName()));
                
                // Delete oldest backups
                for (int i = 0; i < backups.length - 5; i++) {
                    deleteRecursive(backups[i]);
                    Log.d("MMKV", "Deleted old backup: " + backups[i].getName());
                }
            }
            
            Log.d("MMKV", String.format("Automated backup completed: %d instances, %s", 
                                       backedUpCount, timestamp));
        }
    }
    
    private void deleteRecursive(File file) {
        if (file.isDirectory()) {
            File[] children = file.listFiles();
            if (children != null) {
                for (File child : children) {
                    deleteRecursive(child);
                }
            }
        }
        file.delete();
    }
}

Storage Management

Methods for managing MMKV storage files and checking storage status.

/**
 * Remove the storage of the MMKV, including data file and meta file (.crc).
 * Note: The existing instance (if any) will be closed and destroyed.
 * @param mmapID The unique ID of the MMKV instance
 * @return True if removal successful
 */
public static boolean removeStorage(String mmapID);

/**
 * Remove MMKV storage with custom root path.
 * @param mmapID The unique ID of the MMKV instance
 * @param rootPath The folder of the MMKV instance, null for default
 * @return True if removal successful
 */
public 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 file exists
 */
public static boolean checkExist(String mmapID);

/**
 * Check existence of MMKV file with custom root path.
 * @param mmapID The unique ID of the MMKV instance
 * @param rootPath The folder of the MMKV instance, null for default
 * @return True if file exists
 */
public static boolean checkExist(String mmapID, String rootPath);

/**
 * Check whether the MMKV file is valid.
 * Note: Don't use this to check existence - result is undefined on nonexistent files.
 * @param mmapID The unique ID of the MMKV instance
 * @return True if file is valid
 */
public static boolean isFileValid(String mmapID);

/**
 * Check MMKV file validity with custom root path.
 * @param mmapID The unique ID of the MMKV instance
 * @param rootPath The folder of the MMKV instance, null for default
 * @return True if file is valid
 */
public static boolean isFileValid(String mmapID, String rootPath);

Usage Example:

public class MMKVStorageManagementExample {
    
    /**
     * Clean up unused MMKV instances.
     */
    public void cleanupUnusedInstances() {
        String[] instancesToCheck = {"temp_cache", "old_user_data", "deprecated_settings"};
        
        for (String instanceId : instancesToCheck) {
            if (MMKV.checkExist(instanceId)) {
                if (MMKV.isFileValid(instanceId)) {
                    // File exists and is valid - check if still needed
                    if (isInstanceStillNeeded(instanceId)) {
                        Log.d("MMKV", "Keeping instance: " + instanceId);
                    } else {
                        // Remove unused instance
                        boolean removed = MMKV.removeStorage(instanceId);
                        Log.d("MMKV", "Removed unused instance " + instanceId + ": " + removed);
                    }
                } else {
                    Log.w("MMKV", "Invalid file detected: " + instanceId);
                    // Remove corrupted file
                    MMKV.removeStorage(instanceId);
                }
            } else {
                Log.d("MMKV", "Instance doesn't exist: " + instanceId);
            }
        }
    }
    
    /**
     * Health check for all MMKV instances.
     */
    public void performHealthCheck() {
        // Get all MMKV files in default directory
        File mmkvRoot = new File(MMKV.getRootDir());
        File[] mmkvFiles = mmkvRoot.listFiles((dir, name) -> !name.endsWith(".crc"));
        
        if (mmkvFiles != null) {
            for (File file : mmkvFiles) {
                String instanceId = file.getName();
                
                boolean exists = MMKV.checkExist(instanceId);
                boolean valid = exists && MMKV.isFileValid(instanceId);
                
                Log.d("MMKV", String.format("Health check - %s: exists=%b, valid=%b", 
                                           instanceId, exists, valid));
                
                if (exists && !valid) {
                    Log.e("MMKV", "Corrupted MMKV file detected: " + instanceId);
                    // Handle corruption - backup and recreate, or remove
                    handleCorruptedFile(instanceId);
                }
            }
        }
    }
    
    /**
     * Get storage statistics.
     */
    public void getStorageStats() {
        File mmkvRoot = new File(MMKV.getRootDir());
        long totalSize = 0;
        int fileCount = 0;
        
        File[] files = mmkvRoot.listFiles();
        if (files != null) {
            for (File file : files) {
                if (file.isFile()) {
                    totalSize += file.length();
                    fileCount++;
                }
            }
        }
        
        Log.d("MMKV", String.format("Storage stats - Files: %d, Total size: %d bytes (%.2f KB)", 
                                   fileCount, totalSize, totalSize / 1024.0));
        
        // Also check individual instance sizes
        String[] activeInstances = {"user_data", "app_settings", "cache"};
        for (String instanceId : activeInstances) {
            if (MMKV.checkExist(instanceId)) {
                MMKV kv = MMKV.mmkvWithID(instanceId);
                long instanceSize = kv.totalSize();
                long actualSize = kv.actualSize();
                
                Log.d("MMKV", String.format("%s - Total: %d bytes, Used: %d bytes (%.1f%%)", 
                                           instanceId, instanceSize, actualSize, 
                                           (actualSize * 100.0) / instanceSize));
            }
        }
    }
    
    private boolean isInstanceStillNeeded(String instanceId) {
        // Implement your logic to determine if instance is still needed
        // For example, check app settings, user preferences, etc.
        return !instanceId.startsWith("temp_");
    }
    
    private void handleCorruptedFile(String instanceId) {
        Log.w("MMKV", "Handling corrupted file: " + instanceId);
        
        // Try to backup what we can
        try {
            File backupDir = new File(MMKV.getRootDir(), "corrupted_backup");
            backupDir.mkdirs();
            MMKV.backupOneToDirectory(instanceId, backupDir.getAbsolutePath(), null);
        } catch (Exception e) {
            Log.e("MMKV", "Failed to backup corrupted file", e);
        }
        
        // Remove corrupted file
        MMKV.removeStorage(instanceId);
        
        // Optionally recreate with default values
        // recreateWithDefaults(instanceId);
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-com-tencent--mmkv

docs

data-management.md

data-storage.md

encryption.md

index.md

initialization.md

instance-management.md

multi-process.md

namespace.md

tile.json