diff --git a/package/src/MMKV.ts b/package/src/MMKV.ts index 84ee69a6..a4fa00ca 100644 --- a/package/src/MMKV.ts +++ b/package/src/MMKV.ts @@ -1,9 +1,9 @@ -import { AppState } from 'react-native'; import { createMMKV } from './createMMKV'; import { createMockMMKV } from './createMMKV.mock'; import { isTest } from './PlatformChecker'; import type { Configuration } from './NativeMmkv'; import type { Listener, MMKVInterface, NativeMMKV } from './Types'; +import { addMemoryWarningListener } from './MemoryWarningListener'; const onValueChangedListeners = new Map void)[]>(); @@ -26,10 +26,7 @@ export class MMKV implements MMKVInterface { : createMMKV(configuration); this.functionCache = {}; - AppState.addEventListener('memoryWarning', () => { - // when we have a memory warning, delete unused keys by trimming MMKV - this.trim(); - }); + addMemoryWarningListener(this); } private get onValueChangedListeners() { diff --git a/package/src/MemoryWarningListener.ts b/package/src/MemoryWarningListener.ts new file mode 100644 index 00000000..9ac5fbbd --- /dev/null +++ b/package/src/MemoryWarningListener.ts @@ -0,0 +1,29 @@ +import { AppState } from 'react-native'; +import type { NativeEventSubscription } from 'react-native'; +import { MMKVInterface } from './Types'; + +export function addMemoryWarningListener(mmkv: MMKVInterface): void { + if (global.WeakRef != null && global.FinalizationRegistry != null) { + // 1. Weakify MMKV so we can safely use it inside the memoryWarning event listener + const weakMmkv = new WeakRef(mmkv); + const listener = AppState.addEventListener('memoryWarning', () => { + // 0. Everytime we receive a memoryWarning, we try to trim the MMKV instance (if it is still valid) + weakMmkv.deref()?.trim(); + }); + // 2. Add a listener to when the MMKV instance is deleted + const finalization = new FinalizationRegistry( + (l: NativeEventSubscription) => { + // 3. When MMKV is deleted, this listener will be called with the memoryWarning listener. + l.remove(); + } + ); + // 2.1. Bind the listener to the actual MMKV instance. + finalization.register(mmkv, listener); + } else { + // WeakRef/FinalizationRegistry is not implemented in this engine. + // Just add the listener, even if it retains MMKV strong forever. + AppState.addEventListener('memoryWarning', () => { + mmkv.trim(); + }); + } +}