0
# Data Management
1
2
Advanced data management operations including key inspection, file operations, backup/restore capabilities, and performance optimization methods.
3
4
## Capabilities
5
6
### Key Inspection
7
8
Methods for inspecting and analyzing stored keys and their properties.
9
10
```java { .api }
11
/**
12
* Check whether MMKV contains the key.
13
* @param key The key to check
14
* @return True if key exists, false otherwise
15
*/
16
public boolean containsKey(String key);
17
18
/**
19
* Get all keys in the MMKV instance.
20
* @return Array of all keys, or null if no keys exist
21
*/
22
public String[] allKeys();
23
24
/**
25
* Get all non-expired keys in the MMKV instance.
26
* Note: This call has performance costs.
27
* @return Array of non-expired keys, or null if no keys exist
28
*/
29
public String[] allNonExpireKeys();
30
31
/**
32
* Get the total count of all keys.
33
* @return The total number of keys
34
*/
35
public long count();
36
37
/**
38
* Get the total count of all non-expired keys.
39
* Note: This call has performance costs.
40
* @return The total number of non-expired keys
41
*/
42
public long countNonExpiredKeys();
43
```
44
45
**Usage Example:**
46
47
```java
48
MMKV kv = MMKV.defaultMMKV();
49
50
// Add some test data
51
kv.encode("user_id", 123);
52
kv.encode("username", "john_doe");
53
kv.encode("is_premium", true);
54
kv.encode("temp_data", "temporary", MMKV.ExpireInMinute);
55
56
// Check if specific keys exist
57
boolean hasUserId = kv.containsKey("user_id"); // true
58
boolean hasEmail = kv.containsKey("email"); // false
59
60
// Get all keys
61
String[] allKeys = kv.allKeys();
62
if (allKeys != null) {
63
Log.d("MMKV", "Total keys: " + allKeys.length);
64
for (String key : allKeys) {
65
Log.d("MMKV", "Key: " + key);
66
}
67
}
68
69
// Get count of keys
70
long totalCount = kv.count(); // 4
71
long nonExpiredCount = kv.countNonExpiredKeys(); // 3 (after temp_data expires)
72
73
Log.d("MMKV", String.format("Total: %d, Non-expired: %d", totalCount, nonExpiredCount));
74
75
// Get only non-expired keys (more expensive operation)
76
String[] activeKeys = kv.allNonExpireKeys();
77
```
78
79
### Value Size Analysis
80
81
Analyze the size and memory usage of stored values.
82
83
```java { .api }
84
/**
85
* Get the actual size consumption of the key's value.
86
* Note: Might be slightly larger than value's length due to metadata.
87
* @param key The key of the value
88
* @return The size in bytes
89
*/
90
public int getValueSize(String key);
91
92
/**
93
* Get the actual size of the key's value.
94
* Returns string length or byte array length, etc.
95
* @param key The key of the value
96
* @return The actual value size in bytes
97
*/
98
public int getValueActualSize(String key);
99
100
/**
101
* Get the size of the underlying file.
102
* Aligned to disk block size, typically 4K for Android devices.
103
* @return The total file size in bytes
104
*/
105
public long totalSize();
106
107
/**
108
* Get the actual used size of the MMKV instance.
109
* This size might increase and decrease as MMKV does insertion and full write back.
110
* @return The actual used size in bytes
111
*/
112
public long actualSize();
113
```
114
115
**Usage Example:**
116
117
```java
118
MMKV kv = MMKV.defaultMMKV();
119
120
// Store different types of data
121
kv.encode("short_string", "Hello");
122
kv.encode("long_string", "This is a much longer string that will take more space");
123
kv.encode("large_number", 1234567890L);
124
byte[] imageData = new byte[1024 * 100]; // 100KB of data
125
kv.encode("image_data", imageData);
126
127
// Analyze individual value sizes
128
int shortStringSize = kv.getValueSize("short_string"); // ~5 + metadata
129
int shortStringActual = kv.getValueActualSize("short_string"); // 5
130
int longStringSize = kv.getValueSize("long_string");
131
int imageDataSize = kv.getValueSize("image_data"); // ~100KB + metadata
132
133
Log.d("MMKV", String.format("Short string: %d bytes (actual: %d)",
134
shortStringSize, shortStringActual));
135
Log.d("MMKV", String.format("Long string: %d bytes", longStringSize));
136
Log.d("MMKV", String.format("Image data: %d bytes", imageDataSize));
137
138
// Analyze overall file sizes
139
long totalFileSize = kv.totalSize(); // File size on disk (aligned to 4K blocks)
140
long actualUsedSize = kv.actualSize(); // Actual data size used
141
142
Log.d("MMKV", String.format("Total file size: %d bytes (%.2f KB)",
143
totalFileSize, totalFileSize / 1024.0));
144
Log.d("MMKV", String.format("Actual used size: %d bytes (%.2f KB)",
145
actualUsedSize, actualUsedSize / 1024.0));
146
Log.d("MMKV", String.format("Efficiency: %.1f%%",
147
(actualUsedSize * 100.0) / totalFileSize));
148
```
149
150
### Data Removal
151
152
Remove individual keys, multiple keys, or clear all data.
153
154
```java { .api }
155
/**
156
* Remove the value for a specific key.
157
* @param key The key to remove
158
*/
159
public void removeValueForKey(String key);
160
161
/**
162
* Batch remove multiple keys from the MMKV instance.
163
* @param arrKeys Array of keys to be removed
164
*/
165
public void removeValuesForKeys(String[] arrKeys);
166
167
/**
168
* Clear all key-values inside the MMKV instance.
169
* The data file will be trimmed down to pageSize and sync operations called.
170
* For better performance without file trimming, use clearAllWithKeepingSpace().
171
*/
172
public void clearAll();
173
174
/**
175
* Faster clearAll() implementation that keeps the file size.
176
* The file size is kept as previous for later use.
177
*/
178
public void clearAllWithKeepingSpace();
179
```
180
181
**Usage Example:**
182
183
```java
184
MMKV kv = MMKV.defaultMMKV();
185
186
// Add test data
187
kv.encode("keep_this", "important data");
188
kv.encode("temp1", "temporary data 1");
189
kv.encode("temp2", "temporary data 2");
190
kv.encode("temp3", "temporary data 3");
191
kv.encode("delete_this", "data to delete");
192
193
// Remove single key
194
kv.removeValueForKey("delete_this");
195
196
// Remove multiple keys at once (more efficient than individual removes)
197
String[] keysToRemove = {"temp1", "temp2", "temp3"};
198
kv.removeValuesForKeys(keysToRemove);
199
200
// Check what's left
201
String[] remainingKeys = kv.allKeys();
202
Log.d("MMKV", "Remaining keys: " + Arrays.toString(remainingKeys)); // Should show "keep_this"
203
204
// Clear all data (with file trimming for space reclamation)
205
long sizeBefore = kv.totalSize();
206
kv.clearAll();
207
long sizeAfter = kv.totalSize();
208
Log.d("MMKV", String.format("Size before clear: %d, after: %d", sizeBefore, sizeAfter));
209
210
// Alternative: clear all but keep file size for performance
211
kv.encode("test", "data");
212
kv.clearAllWithKeepingSpace(); // Faster, but doesn't reclaim disk space
213
```
214
215
### File Maintenance
216
217
Operations for maintaining and optimizing MMKV file storage.
218
219
```java { .api }
220
/**
221
* Reduce file size after lots of deletions.
222
* The totalSize() of an MMKV instance won't reduce after deleting key-values.
223
* Call this method after lots of deleting if you care about disk usage.
224
* Note: clearAll() has a similar effect.
225
*/
226
public void trim();
227
228
/**
229
* Save all mmap memory to file synchronously.
230
* You don't need to call this normally - MMKV handles persistence automatically.
231
* Use only if you worry about device running out of battery.
232
*/
233
public void sync();
234
235
/**
236
* Save all mmap memory to file asynchronously.
237
* No need to call this unless you worry about losing battery power.
238
*/
239
public void async();
240
241
/**
242
* Clear memory cache of the MMKV instance.
243
* Call this on memory warning to free up RAM.
244
* Any subsequent call will trigger key-values loading from file again.
245
*/
246
public void clearMemoryCache();
247
248
/**
249
* Call this method if the MMKV instance is no longer needed.
250
* Any subsequent call to MMKV instances with the same ID is undefined behavior.
251
*/
252
public void close();
253
```
254
255
**Usage Example:**
256
257
```java
258
public class MMKVMaintenanceExample {
259
260
private MMKV kv;
261
262
public void demonstrateFileMaintenance() {
263
kv = MMKV.mmkvWithID("maintenance_example");
264
265
// Add lots of data
266
for (int i = 0; i < 10000; i++) {
267
kv.encode("key_" + i, "value_" + i);
268
}
269
270
long sizeBefore = kv.totalSize();
271
Log.d("MMKV", "Size before deletions: " + sizeBefore);
272
273
// Delete most of the data
274
for (int i = 0; i < 9000; i++) {
275
kv.removeValueForKey("key_" + i);
276
}
277
278
long sizeAfterDeletion = kv.totalSize();
279
Log.d("MMKV", "Size after deletions: " + sizeAfterDeletion); // Still large
280
281
// Trim file to reclaim space
282
kv.trim();
283
284
long sizeAfterTrim = kv.totalSize();
285
Log.d("MMKV", "Size after trim: " + sizeAfterTrim); // Much smaller
286
287
// Force synchronous save to disk
288
kv.sync();
289
290
// Or use asynchronous save for better performance
291
kv.async();
292
}
293
294
public void handleMemoryPressure() {
295
// Clear memory cache to free RAM
296
kv.clearMemoryCache();
297
Log.d("MMKV", "Memory cache cleared due to memory pressure");
298
}
299
300
@Override
301
protected void onDestroy() {
302
super.onDestroy();
303
// Close MMKV instance when no longer needed
304
if (kv != null) {
305
kv.close();
306
kv = null;
307
}
308
}
309
}
310
```
311
312
### Data Import and Export
313
314
Import data from other sources and export for backup purposes.
315
316
```java { .api }
317
/**
318
* Import all key-value items from another MMKV instance.
319
* @param src The source MMKV instance to import from
320
* @return Count of items imported
321
*/
322
public long importFrom(MMKV src);
323
324
/**
325
* Atomically migrate all key-values from an existing SharedPreferences.
326
* @param preferences The SharedPreferences to import from
327
* @return The total count of key-values imported
328
*/
329
public int importFromSharedPreferences(SharedPreferences preferences);
330
```
331
332
**Usage Example:**
333
334
```java
335
public class MMKVImportExportExample {
336
337
/**
338
* Migrate from SharedPreferences to MMKV.
339
*/
340
public void migrateFromSharedPreferences(Context context) {
341
// Get existing SharedPreferences
342
SharedPreferences oldPrefs = context.getSharedPreferences("user_prefs", Context.MODE_PRIVATE);
343
344
// Create new MMKV instance
345
MMKV newKv = MMKV.mmkvWithID("user_prefs");
346
347
// Import all data from SharedPreferences
348
int importedCount = newKv.importFromSharedPreferences(oldPrefs);
349
350
Log.d("MMKV", "Imported " + importedCount + " items from SharedPreferences");
351
352
// Verify the migration
353
if (importedCount > 0) {
354
// Clear old SharedPreferences after successful migration
355
oldPrefs.edit().clear().apply();
356
Log.d("MMKV", "Successfully migrated to MMKV");
357
}
358
}
359
360
/**
361
* Copy data between MMKV instances.
362
*/
363
public void copyDataBetweenInstances() {
364
// Source instance with data
365
MMKV sourceKv = MMKV.mmkvWithID("source_data");
366
sourceKv.encode("user_id", 123);
367
sourceKv.encode("username", "john");
368
sourceKv.encode("settings", "dark_mode=true");
369
370
// Destination instance
371
MMKV destKv = MMKV.mmkvWithID("backup_data");
372
373
// Import all data from source to destination
374
long importedCount = destKv.importFrom(sourceKv);
375
376
Log.d("MMKV", "Imported " + importedCount + " items to backup");
377
378
// Verify the copy
379
String username = destKv.decodeString("username"); // "john"
380
int userId = destKv.decodeInt("user_id"); // 123
381
382
Log.d("MMKV", String.format("Verified backup: user=%s, id=%d", username, userId));
383
}
384
385
/**
386
* Create incremental backup.
387
*/
388
public void createIncrementalBackup() {
389
MMKV mainKv = MMKV.defaultMMKV();
390
MMKV backupKv = MMKV.mmkvWithID("incremental_backup");
391
392
// Get timestamp of last backup
393
long lastBackupTime = backupKv.decodeLong("last_backup_time", 0);
394
395
// Import all current data (MMKV handles duplicates efficiently)
396
long importedCount = backupKv.importFrom(mainKv);
397
398
// Update backup timestamp
399
backupKv.encode("last_backup_time", System.currentTimeMillis());
400
401
Log.d("MMKV", String.format("Incremental backup: %d items, last backup: %d",
402
importedCount, lastBackupTime));
403
}
404
}
405
```
406
407
### Backup and Restore Operations
408
409
File-level backup and restore operations for data protection.
410
411
```java { .api }
412
/**
413
* Backup one MMKV instance to destination directory.
414
* @param mmapID The MMKV ID to backup
415
* @param dstDir The backup destination directory
416
* @param rootPath The customize root path of the MMKV, null for default root
417
* @return True if backup successful
418
*/
419
public static boolean backupOneToDirectory(String mmapID, String dstDir, String rootPath);
420
421
/**
422
* Restore one MMKV instance from source directory.
423
* @param mmapID The MMKV ID to restore
424
* @param srcDir The restore source directory
425
* @param rootPath The customize root path of the MMKV, null for default root
426
* @return True if restore successful
427
*/
428
public static boolean restoreOneMMKVFromDirectory(String mmapID, String srcDir, String rootPath);
429
430
/**
431
* Backup all MMKV instances from default root dir to destination directory.
432
* @param dstDir The backup destination directory
433
* @return Count of MMKV instances successfully backed up
434
*/
435
public static long backupAllToDirectory(String dstDir);
436
437
/**
438
* Restore all MMKV instances from source directory to default root dir.
439
* @param srcDir The restore source directory
440
* @return Count of MMKV instances successfully restored
441
*/
442
public static long restoreAllFromDirectory(String srcDir);
443
```
444
445
**Usage Example:**
446
447
```java
448
public class MMKVBackupRestoreExample {
449
450
/**
451
* Create backup of specific MMKV instances.
452
*/
453
public void backupSpecificInstances(Context context) {
454
// Create backup directory
455
File backupDir = new File(context.getExternalFilesDir(null), "mmkv_backup");
456
if (!backupDir.exists()) {
457
backupDir.mkdirs();
458
}
459
460
String backupPath = backupDir.getAbsolutePath();
461
462
// Backup specific instances
463
boolean userBackup = MMKV.backupOneToDirectory("user_data", backupPath, null);
464
boolean settingsBackup = MMKV.backupOneToDirectory("app_settings", backupPath, null);
465
466
Log.d("MMKV", String.format("Backup results - User: %b, Settings: %b",
467
userBackup, settingsBackup));
468
469
if (userBackup && settingsBackup) {
470
// Store backup metadata
471
MMKV backupMeta = MMKV.mmkvWithID("backup_metadata");
472
backupMeta.encode("last_backup_time", System.currentTimeMillis());
473
backupMeta.encode("backup_path", backupPath);
474
backupMeta.encode("backup_count", 2);
475
}
476
}
477
478
/**
479
* Backup all MMKV instances.
480
*/
481
public void backupAllInstances(Context context) {
482
File backupDir = new File(context.getExternalFilesDir(null), "mmkv_full_backup");
483
backupDir.mkdirs();
484
485
// Backup all instances
486
long backedUpCount = MMKV.backupAllToDirectory(backupDir.getAbsolutePath());
487
488
Log.d("MMKV", "Backed up " + backedUpCount + " MMKV instances");
489
490
// Create backup manifest
491
MMKV manifest = MMKV.mmkvWithID("backup_manifest");
492
manifest.encode("backup_timestamp", System.currentTimeMillis());
493
manifest.encode("backup_count", backedUpCount);
494
manifest.encode("backup_type", "full");
495
}
496
497
/**
498
* Restore from backup.
499
*/
500
public void restoreFromBackup(String backupPath) {
501
try {
502
// Restore specific instances
503
boolean userRestored = MMKV.restoreOneMMKVFromDirectory("user_data", backupPath, null);
504
boolean settingsRestored = MMKV.restoreOneMMKVFromDirectory("app_settings", backupPath, null);
505
506
if (userRestored && settingsRestored) {
507
Log.d("MMKV", "Successfully restored specific instances");
508
}
509
510
// Or restore all instances
511
long restoredCount = MMKV.restoreAllFromDirectory(backupPath);
512
Log.d("MMKV", "Restored " + restoredCount + " instances from backup");
513
514
} catch (Exception e) {
515
Log.e("MMKV", "Failed to restore from backup", e);
516
}
517
}
518
519
/**
520
* Automated backup with rotation.
521
*/
522
public void automatedBackupWithRotation(Context context) {
523
File backupRoot = new File(context.getExternalFilesDir(null), "mmkv_backups");
524
backupRoot.mkdirs();
525
526
// Create timestamped backup directory
527
String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US)
528
.format(new Date());
529
File currentBackup = new File(backupRoot, "backup_" + timestamp);
530
currentBackup.mkdirs();
531
532
// Perform backup
533
long backedUpCount = MMKV.backupAllToDirectory(currentBackup.getAbsolutePath());
534
535
if (backedUpCount > 0) {
536
// Keep only last 5 backups
537
File[] backups = backupRoot.listFiles((dir, name) -> name.startsWith("backup_"));
538
if (backups != null && backups.length > 5) {
539
Arrays.sort(backups, (a, b) -> a.getName().compareTo(b.getName()));
540
541
// Delete oldest backups
542
for (int i = 0; i < backups.length - 5; i++) {
543
deleteRecursive(backups[i]);
544
Log.d("MMKV", "Deleted old backup: " + backups[i].getName());
545
}
546
}
547
548
Log.d("MMKV", String.format("Automated backup completed: %d instances, %s",
549
backedUpCount, timestamp));
550
}
551
}
552
553
private void deleteRecursive(File file) {
554
if (file.isDirectory()) {
555
File[] children = file.listFiles();
556
if (children != null) {
557
for (File child : children) {
558
deleteRecursive(child);
559
}
560
}
561
}
562
file.delete();
563
}
564
}
565
```
566
567
### Storage Management
568
569
Methods for managing MMKV storage files and checking storage status.
570
571
```java { .api }
572
/**
573
* Remove the storage of the MMKV, including data file and meta file (.crc).
574
* Note: The existing instance (if any) will be closed and destroyed.
575
* @param mmapID The unique ID of the MMKV instance
576
* @return True if removal successful
577
*/
578
public static boolean removeStorage(String mmapID);
579
580
/**
581
* Remove MMKV storage with custom root path.
582
* @param mmapID The unique ID of the MMKV instance
583
* @param rootPath The folder of the MMKV instance, null for default
584
* @return True if removal successful
585
*/
586
public static boolean removeStorage(String mmapID, String rootPath);
587
588
/**
589
* Check existence of the MMKV file.
590
* @param mmapID The unique ID of the MMKV instance
591
* @return True if file exists
592
*/
593
public static boolean checkExist(String mmapID);
594
595
/**
596
* Check existence of MMKV file with custom root path.
597
* @param mmapID The unique ID of the MMKV instance
598
* @param rootPath The folder of the MMKV instance, null for default
599
* @return True if file exists
600
*/
601
public static boolean checkExist(String mmapID, String rootPath);
602
603
/**
604
* Check whether the MMKV file is valid.
605
* Note: Don't use this to check existence - result is undefined on nonexistent files.
606
* @param mmapID The unique ID of the MMKV instance
607
* @return True if file is valid
608
*/
609
public static boolean isFileValid(String mmapID);
610
611
/**
612
* Check MMKV file validity with custom root path.
613
* @param mmapID The unique ID of the MMKV instance
614
* @param rootPath The folder of the MMKV instance, null for default
615
* @return True if file is valid
616
*/
617
public static boolean isFileValid(String mmapID, String rootPath);
618
```
619
620
**Usage Example:**
621
622
```java
623
public class MMKVStorageManagementExample {
624
625
/**
626
* Clean up unused MMKV instances.
627
*/
628
public void cleanupUnusedInstances() {
629
String[] instancesToCheck = {"temp_cache", "old_user_data", "deprecated_settings"};
630
631
for (String instanceId : instancesToCheck) {
632
if (MMKV.checkExist(instanceId)) {
633
if (MMKV.isFileValid(instanceId)) {
634
// File exists and is valid - check if still needed
635
if (isInstanceStillNeeded(instanceId)) {
636
Log.d("MMKV", "Keeping instance: " + instanceId);
637
} else {
638
// Remove unused instance
639
boolean removed = MMKV.removeStorage(instanceId);
640
Log.d("MMKV", "Removed unused instance " + instanceId + ": " + removed);
641
}
642
} else {
643
Log.w("MMKV", "Invalid file detected: " + instanceId);
644
// Remove corrupted file
645
MMKV.removeStorage(instanceId);
646
}
647
} else {
648
Log.d("MMKV", "Instance doesn't exist: " + instanceId);
649
}
650
}
651
}
652
653
/**
654
* Health check for all MMKV instances.
655
*/
656
public void performHealthCheck() {
657
// Get all MMKV files in default directory
658
File mmkvRoot = new File(MMKV.getRootDir());
659
File[] mmkvFiles = mmkvRoot.listFiles((dir, name) -> !name.endsWith(".crc"));
660
661
if (mmkvFiles != null) {
662
for (File file : mmkvFiles) {
663
String instanceId = file.getName();
664
665
boolean exists = MMKV.checkExist(instanceId);
666
boolean valid = exists && MMKV.isFileValid(instanceId);
667
668
Log.d("MMKV", String.format("Health check - %s: exists=%b, valid=%b",
669
instanceId, exists, valid));
670
671
if (exists && !valid) {
672
Log.e("MMKV", "Corrupted MMKV file detected: " + instanceId);
673
// Handle corruption - backup and recreate, or remove
674
handleCorruptedFile(instanceId);
675
}
676
}
677
}
678
}
679
680
/**
681
* Get storage statistics.
682
*/
683
public void getStorageStats() {
684
File mmkvRoot = new File(MMKV.getRootDir());
685
long totalSize = 0;
686
int fileCount = 0;
687
688
File[] files = mmkvRoot.listFiles();
689
if (files != null) {
690
for (File file : files) {
691
if (file.isFile()) {
692
totalSize += file.length();
693
fileCount++;
694
}
695
}
696
}
697
698
Log.d("MMKV", String.format("Storage stats - Files: %d, Total size: %d bytes (%.2f KB)",
699
fileCount, totalSize, totalSize / 1024.0));
700
701
// Also check individual instance sizes
702
String[] activeInstances = {"user_data", "app_settings", "cache"};
703
for (String instanceId : activeInstances) {
704
if (MMKV.checkExist(instanceId)) {
705
MMKV kv = MMKV.mmkvWithID(instanceId);
706
long instanceSize = kv.totalSize();
707
long actualSize = kv.actualSize();
708
709
Log.d("MMKV", String.format("%s - Total: %d bytes, Used: %d bytes (%.1f%%)",
710
instanceId, instanceSize, actualSize,
711
(actualSize * 100.0) / instanceSize));
712
}
713
}
714
}
715
716
private boolean isInstanceStillNeeded(String instanceId) {
717
// Implement your logic to determine if instance is still needed
718
// For example, check app settings, user preferences, etc.
719
return !instanceId.startsWith("temp_");
720
}
721
722
private void handleCorruptedFile(String instanceId) {
723
Log.w("MMKV", "Handling corrupted file: " + instanceId);
724
725
// Try to backup what we can
726
try {
727
File backupDir = new File(MMKV.getRootDir(), "corrupted_backup");
728
backupDir.mkdirs();
729
MMKV.backupOneToDirectory(instanceId, backupDir.getAbsolutePath(), null);
730
} catch (Exception e) {
731
Log.e("MMKV", "Failed to backup corrupted file", e);
732
}
733
734
// Remove corrupted file
735
MMKV.removeStorage(instanceId);
736
737
// Optionally recreate with default values
738
// recreateWithDefaults(instanceId);
739
}
740
}
741
```