Reduce iOS memory pressure: lightbox windowing, memory warning handler

- Lightbox pager: only mount ±1 neighbor of the current page so a
  multi-image post no longer decodes every fullsize image up front.
- App: respond to iOS memoryWarning events by clearing expo-image's
  in-memory cache, giving the GC a stronger hint before jetsam.
- GIF picker: priority="low" + recyclingKey on item Image. Minor; the
  picker's masonry grid still needs proper row virtualization.

Hypothesis-driven against APP-D9 breadcrumb patterns; needs TestFlight
validation before claiming any rate reduction.
This commit is contained in:
vineyardbovines
2026-06-03 13:56:03 -04:00
parent 9df4add435
commit eb4bdefbfe
3 changed files with 32 additions and 16 deletions
+12
View File
@@ -1,12 +1,14 @@
import '#/logger/sentry/setup'
import {Fragment, useEffect, useState} from 'react'
import {DeviceEventEmitter} from 'react-native'
import {GestureHandlerRootView} from 'react-native-gesture-handler'
import {KeyboardProvider as KeyboardControllerProvider} from 'react-native-keyboard-controller'
import {
initialWindowMetrics,
SafeAreaProvider,
} from 'react-native-safe-area-context'
import {Image} from 'expo-image'
import * as ScreenOrientation from 'expo-screen-orientation'
import * as SplashScreen from 'expo-splash-screen'
import * as SystemUI from 'expo-system-ui'
@@ -141,6 +143,16 @@ function InnerApp() {
})
}, [l])
// Respond to iOS memory warnings before the OS jetsams us. expo-image trims
// its own cache on warning, but explicitly clearing it gives the GC a stronger
// hint and frees decoded bitmaps no longer in active use.
useEffect(() => {
const sub = DeviceEventEmitter.addListener('memoryWarning', () => {
void Image.clearMemoryCache()
})
return () => sub.remove()
}, [])
return (
<Alf theme={theme}>
<ThemeProvider theme={theme}>
+18 -16
View File
@@ -415,22 +415,24 @@ function ImageView({
style={styles.pager}>
{images.map((imageSrc, i) => (
<View key={`${i}-${imageSrc.uri}`}>
<LightboxImage
onTap={onTap}
onZoom={onZoom}
imageSrc={imageSrc}
onRequestClose={handleRequestClose}
isScrollViewBeingDragged={isDragging}
showControls={showControls}
safeAreaRef={safeAreaRef}
isScaled={isScaled}
isFlyingAway={isFlyingAway}
isActive={i === imageIndex}
dismissSwipeTranslateY={dismissSwipeTranslateY}
openProgress={openProgress}
thumbRects={thumbRects}
imageIndex={i}
/>
{Math.abs(i - imageIndex) <= 1 ? (
<LightboxImage
onTap={onTap}
onZoom={onZoom}
imageSrc={imageSrc}
onRequestClose={handleRequestClose}
isScrollViewBeingDragged={isDragging}
showControls={showControls}
safeAreaRef={safeAreaRef}
isScaled={isScaled}
isFlyingAway={isFlyingAway}
isActive={i === imageIndex}
dismissSwipeTranslateY={dismissSwipeTranslateY}
openProgress={openProgress}
thumbRects={thumbRects}
imageIndex={i}
/>
) : null}
</View>
))}
</PagerView>
@@ -52,6 +52,8 @@ export function GifPickerItem({
accessibilityLabel={gif.title}
accessibilityHint=""
cachePolicy="none"
priority="low"
recyclingKey={gif.id}
accessibilityIgnoresInvertColors
/>
)}