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:
+12
@@ -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}>
|
||||
|
||||
@@ -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
|
||||
/>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user