High-performance, cross-platform key-value storage framework with static C++ linking for Android applications
—
MMKV provides robust multi-process synchronization capabilities, allowing safe concurrent access across Android processes with file locking, content change notifications, and automatic synchronization.
MMKV provides inter-process exclusive locking for safe concurrent access across multiple processes.
/**
* Exclusively inter-process lock the MMKV instance.
* It will block and wait until it successfully locks the file.
* It will make no effect if the MMKV instance is created with SINGLE_PROCESS_MODE.
*/
void lock();
/**
* Exclusively inter-process unlock the MMKV instance.
* It will make no effect if the MMKV instance is created with SINGLE_PROCESS_MODE.
*/
void unlock();
/**
* Try exclusively inter-process lock the MMKV instance.
* It will not block if the file has already been locked by another process.
* It will make no effect if the MMKV instance is created with SINGLE_PROCESS_MODE.
* @return True if successfully locked, otherwise return immediately with False
*/
boolean tryLock();Usage Examples:
// Create multi-process MMKV instance
MMKV sharedKv = MMKV.mmkvWithID("shared_data", MMKV.MULTI_PROCESS_MODE);
// Blocking lock - waits until lock is acquired
sharedKv.lock();
try {
// Critical section - only one process can access at a time
sharedKv.encode("shared_counter", sharedKv.decodeInt("shared_counter", 0) + 1);
sharedKv.encode("last_modified", System.currentTimeMillis());
} finally {
// Always unlock in finally block
sharedKv.unlock();
}
// Non-blocking lock attempt
if (sharedKv.tryLock()) {
try {
// Got the lock, perform operations
sharedKv.encode("optional_update", "updated");
} finally {
sharedKv.unlock();
}
} else {
Log.d("MMKV", "Could not acquire lock, skipping update");
}MMKV provides explicit synchronization methods for ensuring data persistence, though data is normally persisted immediately.
/**
* 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.
*/
void sync();
/**
* Save all mmap memory to file asynchronously.
* No need to call this unless you worry about the device running out of battery.
*/
void async();Usage Examples:
MMKV kv = MMKV.mmkvWithID("important_data");
// Store critical data
kv.encode("critical_setting", importantValue);
// Force synchronous write to disk (usually not needed)
kv.sync();
// Or force asynchronous write
kv.async();
// Note: MMKV automatically persists data immediately, these calls are optionalMMKV provides inter-process content change notifications to detect when data is modified by other processes.
/**
* Register for MMKV inter-process content change notification.
* The notification will trigger only when any method is manually called on the MMKV instance.
* For example checkContentChangedByOuterProcess().
* @param notify The notification handler
*/
static void registerContentChangeNotify(MMKVContentChangeNotification notify);
/**
* Unregister for MMKV inter-process content change notification.
*/
static void unregisterContentChangeNotify();
/**
* Check inter-process content change manually.
*/
void checkContentChangedByOuterProcess();Usage Examples:
// Set up content change notification
MMKV.registerContentChangeNotify(new MMKVContentChangeNotification() {
@Override
public void onContentChangedByOuterProcess(String mmapID) {
Log.d("MMKV", "Content changed in instance: " + mmapID);
// Refresh UI or reload data as needed
if ("shared_config".equals(mmapID)) {
reloadConfiguration();
}
}
});
// In your activity or service
MMKV sharedConfig = MMKV.mmkvWithID("shared_config", MMKV.MULTI_PROCESS_MODE);
// Periodically check for changes from other processes
private void checkForUpdates() {
sharedConfig.checkContentChangedByOuterProcess();
// If content changed, onContentChangedByOuterProcess() will be called
}
// Clean up when done
@Override
protected void onDestroy() {
super.onDestroy();
MMKV.unregisterContentChangeNotify();
}MMKV provides utilities for managing and validating process modes to prevent conflicts.
/**
* Manually enable the process mode checker.
* By default, it's automatically enabled in DEBUG build, and disabled in RELEASE build.
* If it's enabled, MMKV will throw exceptions when an MMKV instance is created with mismatch process mode.
*/
static void enableProcessModeChecker();
/**
* Manually disable the process mode checker.
* By default, it's automatically enabled in DEBUG build, and disabled in RELEASE build.
* If it's enabled, MMKV will throw exceptions when an MMKV instance is created with mismatch process mode.
*/
static void disableProcessModeChecker();
/**
* Check if this instance is in multi-process mode.
* @return True if in multi-process mode, False otherwise
*/
boolean isMultiProcess();
/**
* Check if this instance is in read-only mode.
* @return True if in read-only mode, False otherwise
*/
boolean isReadOnly();Usage Examples:
// Enable strict process mode checking for debugging
MMKV.enableProcessModeChecker();
// Create instances
MMKV singleKv = MMKV.mmkvWithID("single_data", MMKV.SINGLE_PROCESS_MODE);
MMKV multiKv = MMKV.mmkvWithID("multi_data", MMKV.MULTI_PROCESS_MODE);
// Verify process modes
Log.d("MMKV", "Single KV multi-process: " + singleKv.isMultiProcess()); // false
Log.d("MMKV", "Multi KV multi-process: " + multiKv.isMultiProcess()); // true
// This would throw an exception if process mode checker is enabled
// and "multi_data" was previously opened with SINGLE_PROCESS_MODE
try {
MMKV conflictKv = MMKV.mmkvWithID("multi_data", MMKV.SINGLE_PROCESS_MODE);
} catch (IllegalArgumentException e) {
Log.e("MMKV", "Process mode conflict: " + e.getMessage());
}
// Disable checking for production
MMKV.disableProcessModeChecker();MMKV supports Anonymous Shared Memory (ashmem) for high-performance inter-process data sharing without disk persistence.
/**
* Create an MMKV instance base on Anonymous Shared Memory, aka not synced to any disk files.
* @param context The context of Android App, usually from Application
* @param mmapID The unique ID of the MMKV instance
* @param size The maximum size of the underlying Anonymous Shared Memory.
* Anonymous Shared Memory on Android can't grow dynamically, must set an appropriate size on creation
* @param mode The process mode of the MMKV instance, defaults to SINGLE_PROCESS_MODE
* @param cryptKey The encryption key of the MMKV instance (no more than 16 bytes)
* @throws RuntimeException if there's a runtime error
*/
static MMKV mmkvWithAshmemID(Context context, String mmapID, int size, int mode, String cryptKey);
/**
* @return The file descriptor of the ashmem of the MMKV file
*/
int ashmemFD();
/**
* @return The file descriptor of the ashmem of the MMKV crc file
*/
int ashmemMetaFD();Usage Examples:
// Create ashmem instance for inter-process communication
MMKV ashmemKv = MMKV.mmkvWithAshmemID(
this,
"ipc_data",
1024 * 1024, // 1MB max size
MMKV.MULTI_PROCESS_MODE,
null // No encryption
);
// Use like regular MMKV instance
ashmemKv.encode("shared_message", "Hello from process A");
ashmemKv.encode("shared_timestamp", System.currentTimeMillis());
// Get file descriptors for passing to other processes
int dataFD = ashmemKv.ashmemFD();
int metaFD = ashmemKv.ashmemMetaFD();
// Pass these FDs to other processes via Binder/AIDL
// The receiving process can create MMKV instance from FDsGuidelines and patterns for effective multi-process MMKV usage.
// Example multi-process architecture
public class SharedDataManager {
private static final String SHARED_INSTANCE_ID = "app_shared_data";
private final MMKV sharedKv;
public SharedDataManager(Context context) {
// Always use MULTI_PROCESS_MODE for shared data
sharedKv = MMKV.mmkvWithID(SHARED_INSTANCE_ID, MMKV.MULTI_PROCESS_MODE);
// Set up change notifications
MMKV.registerContentChangeNotify(this::onContentChanged);
}
public void updateSharedConfig(String key, Object value) {
sharedKv.lock();
try {
// Update with timestamp for conflict resolution
sharedKv.encode(key + "_timestamp", System.currentTimeMillis());
if (value instanceof String) {
sharedKv.encode(key, (String) value);
} else if (value instanceof Integer) {
sharedKv.encode(key, (Integer) value);
}
// Handle other types...
} finally {
sharedKv.unlock();
}
}
public <T> T getSharedConfig(String key, Class<T> type, T defaultValue) {
// Check for updates from other processes
sharedKv.checkContentChangedByOuterProcess();
if (type == String.class) {
return (T) sharedKv.decodeString(key, (String) defaultValue);
} else if (type == Integer.class) {
return (T) Integer.valueOf(sharedKv.decodeInt(key, (Integer) defaultValue));
}
// Handle other types...
return defaultValue;
}
private void onContentChanged(String mmapID) {
if (SHARED_INSTANCE_ID.equals(mmapID)) {
// Notify UI components about data changes
LocalBroadcastManager.getInstance(context)
.sendBroadcast(new Intent("SHARED_DATA_CHANGED"));
}
}
}/**
* Inter-process content change notification.
* Triggered by any method call, such as getXXX() or setXXX() or checkContentChangedByOuterProcess().
*/
interface MMKVContentChangeNotification {
/**
* Inter-process content change notification.
* Triggered by any method call, such as getXXX() or setXXX() or checkContentChangedByOuterProcess().
* @param mmapID The unique ID of the changed MMKV instance
*/
void onContentChangedByOuterProcess(String mmapID);
}
/**
* A helper class for MMKV based on Anonymous Shared Memory.
*/
class ParcelableMMKV implements Parcelable {
/**
* Create from existing MMKV instance
* @param mmkv The MMKV instance to wrap
*/
ParcelableMMKV(MMKV mmkv);
/**
* Convert back to MMKV instance
* @return MMKV instance, or null if invalid
*/
MMKV toMMKV();
// Parcelable implementation for passing between processes
int describeContents();
void writeToParcel(Parcel dest, int flags);
static final Parcelable.Creator<ParcelableMMKV> CREATOR;
}
/**
* A helper class for getting process information
*/
class MMKVContentProvider extends ContentProvider {
/**
* Get process name by process ID
* @param context Application context
* @param pid Process ID
* @return Process name or empty string if not found
*/
static String getProcessNameByPID(Context context, int pid);
/**
* Get content provider URI for ashmem operations
* @param context Application context
* @return Content provider URI, or null if not configured
*/
static Uri contentUri(Context context);
}/**
* Single-process mode. The default mode on an MMKV instance.
*/
static final int SINGLE_PROCESS_MODE = 1;
/**
* Multi-process mode.
* To enable multi-process accessing of an MMKV instance, you must set this mode whenever you getting that instance.
*/
static final int MULTI_PROCESS_MODE = 2;
/**
* Read-only mode.
*/
static final int READ_ONLY_MODE = 32;Install with Tessl CLI
npx tessl i tessl/maven-com-tencent--mmkv-static