feat: 优化webp加载,增加安卓堆内存解决OOM问题
This commit is contained in:
parent
4ffaadeb7d
commit
f557fb74b3
|
|
@ -78,7 +78,10 @@ const Img = forwardRef<ExpoImage, ImgProps>((props, ref) => {
|
|||
style: [style, imageStyle],
|
||||
ref,
|
||||
source: imageSource,
|
||||
// 使用 disk 缓存策略,减少内存占用
|
||||
cachePolicy: 'disk' as const,
|
||||
// 添加内存缓存上限,当内存紧张时优先释放
|
||||
recyclingKey: typeof src === 'string' ? src : undefined,
|
||||
errorSource,
|
||||
transition: { duration: 200, effect: 'cross-dissolve' as const },
|
||||
...reset,
|
||||
|
|
|
|||
|
|
@ -127,8 +127,10 @@ const VideoBox = ({ url, needWeb = true, width = 256, style, autoplay = true, ..
|
|||
// 移除 key 避免组件重建导致闪烁,使用 transition 实现平滑切换
|
||||
<Image
|
||||
ref={imageRef}
|
||||
// cachePolicy="memory-disk"
|
||||
// 只使用 disk 缓存,减少内存占用
|
||||
cachePolicy="disk"
|
||||
// 添加 recyclingKey 帮助内存回收
|
||||
recyclingKey={urlFinal}
|
||||
source={{ uri: urlFinal }}
|
||||
style={style as any}
|
||||
autoplay={autoplay}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
const withCmakeVersion = require('./plugins/withCmakeVersion')
|
||||
|
||||
export const PROJECT_ID = 'c951a6a3-e1d8-4e39-8636-c476da1fe5be'
|
||||
export const APPNAME = 'duooomi'
|
||||
export const EXPO_PROJECT = 'duooomi'
|
||||
|
|
@ -100,7 +98,8 @@ export default ({ config }) => {
|
|||
'expo-router',
|
||||
'expo-native-alipay',
|
||||
'expo-wechat',
|
||||
// [withCmakeVersion, { version: '4.1.2' }],
|
||||
'./plugins/withLargeHeap',
|
||||
// ['./plugins/withCmakeVersion', { version: '4.1.2' }],
|
||||
|
||||
[
|
||||
'@sentry/react-native/expo',
|
||||
|
|
@ -112,11 +111,20 @@ export default ({ config }) => {
|
|||
],
|
||||
|
||||
[
|
||||
// expo-build-properties是另外一个expo官方的插件,它能让你自定义很多构建阶段的参数,包括自定义混淆规则和maven仓库等。
|
||||
// 记得先npx expo install expo-build-properties
|
||||
'expo-build-properties',
|
||||
{
|
||||
ios: {
|
||||
useFrameworks: 'static',
|
||||
},
|
||||
android: {
|
||||
enableProguardInReleaseBuilds: true,
|
||||
enableShrinkResourcesInReleaseBuilds: true,
|
||||
// 增加 Java 堆内存
|
||||
packagingOptions: {
|
||||
pickFirst: ['**/libc++_shared.so', '**/libjsc.so'],
|
||||
},
|
||||
// 设置 JVM 参数
|
||||
jvmArgs: ['-Xmx4096m', '-XX:MaxMetaspaceSize=512m'],
|
||||
extraProguardRules: `-keep class com.tencent.mm.opensdk.** {
|
||||
*;
|
||||
}
|
||||
|
|
@ -131,6 +139,7 @@ export default ({ config }) => {
|
|||
},
|
||||
},
|
||||
],
|
||||
|
||||
[
|
||||
'react-native-ble-plx',
|
||||
{
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import BannerSection from '@/components/BannerSection'
|
|||
import { useTemplateActions } from '@/hooks/actions/use-template-actions'
|
||||
import { useTemplates } from '@/hooks/data/use-templates'
|
||||
import { userBalanceStore, userStore } from '@/stores'
|
||||
import { screenHeight, screenWidth, uploadFile } from '@/utils'
|
||||
import { screenWidth, uploadFile } from '@/utils'
|
||||
|
||||
const CATEGORY_ID = process.env.EXPO_PUBLIC_GENERATE_GROUP_ID
|
||||
|
||||
|
|
@ -300,7 +300,7 @@ const Generate = observer(function Generate() {
|
|||
<FlashList
|
||||
contentContainerStyle={{ paddingHorizontal: 12, paddingBottom: 200 }}
|
||||
data={displayTemplates}
|
||||
drawDistance={screenHeight}
|
||||
drawDistance={300}
|
||||
// @ts-ignore
|
||||
estimatedItemSize={itemWidth}
|
||||
extraData={selectedTemplateId}
|
||||
|
|
|
|||
|
|
@ -364,16 +364,16 @@ const Index = observer(function Index() {
|
|||
// 快速滑动时可能为空,保留上次状态
|
||||
if (currentVisible.size === 0 && visibleIdsRef.current.size > 0) return
|
||||
|
||||
// 添加前后缓冲(6个)
|
||||
// 添加前后缓冲(减少到3个以降低内存占用)
|
||||
if (viewableItems.length > 0 && allItems.length > 0) {
|
||||
const first = viewableItems[0]?.index ?? 0
|
||||
const last = viewableItems[viewableItems.length - 1]?.index ?? first
|
||||
|
||||
if (first !== null && last !== null) {
|
||||
for (let i = Math.max(0, first - 12); i < first; i++) {
|
||||
for (let i = Math.max(0, first - 6); i < first; i++) {
|
||||
if (allItems[i]) currentVisible.add(allItems[i].id)
|
||||
}
|
||||
for (let i = last + 1; i < Math.min(allItems.length, last + 13); i++) {
|
||||
for (let i = last + 1; i < Math.min(allItems.length, last + 7); i++) {
|
||||
currentVisible.add(allItems[i].id)
|
||||
}
|
||||
}
|
||||
|
|
@ -391,7 +391,7 @@ const Index = observer(function Index() {
|
|||
isSelected={selectedId === item.id}
|
||||
item={item}
|
||||
itemWidth={ITEM_WIDTH}
|
||||
isVisible={index < 12 || visibleIdsRef.current.has(item.id)}
|
||||
isVisible={index < 9 || visibleIdsRef.current.has(item.id)}
|
||||
onSelect={() => setSelectedItem(item)}
|
||||
/>
|
||||
),
|
||||
|
|
@ -426,7 +426,7 @@ const Index = observer(function Index() {
|
|||
onEndReached={handleLoadMore}
|
||||
maxItemsInRecyclePool={0}
|
||||
removeClippedSubviews={true}
|
||||
drawDistance={600}
|
||||
drawDistance={300}
|
||||
onEndReachedThreshold={0.3}
|
||||
refreshControl={<RefreshControl colors={['#FFE500']} refreshing={refreshing} onRefresh={handleRefresh} />}
|
||||
renderItem={renderItem}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ module.exports = function (api) {
|
|||
'babel-preset-expo',
|
||||
{
|
||||
jsxImportSource: 'nativewind',
|
||||
// 禁用 loose 模式,使用 assumptions 代替
|
||||
loose: false,
|
||||
},
|
||||
],
|
||||
'nativewind/babel',
|
||||
|
|
|
|||
|
|
@ -21,7 +21,8 @@ const BannerSection = memo<BannerProps>(function Banner({ bgVideo }) {
|
|||
|
||||
return (
|
||||
<Block className="absolute inset-0 z-0 overflow-hidden">
|
||||
<VideoBox style={{ width: screenWidth, height: screenHeight }} url={bgUrl} width={512} />
|
||||
{/* 使用较小的分辨率降低内存占用 */}
|
||||
<VideoBox style={{ width: screenWidth, height: screenHeight }} url={bgUrl} width={360} />
|
||||
|
||||
<Block className="absolute inset-0">
|
||||
<Svg height="100%" preserveAspectRatio="none" viewBox="0 0 400 800" width="100%">
|
||||
|
|
|
|||
|
|
@ -15,10 +15,7 @@ android {
|
|||
`
|
||||
|
||||
if (!buildGradle.includes('externalNativeBuild')) {
|
||||
config.modResults.contents = buildGradle.replace(
|
||||
androidBlockPattern,
|
||||
cmakeConfig
|
||||
)
|
||||
config.modResults.contents = buildGradle.replace(androidBlockPattern, cmakeConfig)
|
||||
}
|
||||
|
||||
return config
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
const { withAndroidManifest } = require('@expo/config-plugins')
|
||||
|
||||
/**
|
||||
* 为 Android 应用启用 largeHeap 模式
|
||||
* 这将允许应用使用更大的堆内存,避免因图片/视频加载导致的内存不足
|
||||
*/
|
||||
const withLargeHeap = (config) => {
|
||||
return withAndroidManifest(config, (config) => {
|
||||
const androidManifest = config.modResults.manifest
|
||||
|
||||
// 确保 application 节点存在
|
||||
if (!androidManifest.application) {
|
||||
androidManifest.application = [{}]
|
||||
}
|
||||
|
||||
const application = androidManifest.application[0]
|
||||
|
||||
// 设置 largeHeap 为 true
|
||||
application.$['android:largeHeap'] = 'true'
|
||||
|
||||
// 可选:启用硬件加速
|
||||
if (!application.$['android:hardwareAccelerated']) {
|
||||
application.$['android:hardwareAccelerated'] = 'true'
|
||||
}
|
||||
|
||||
console.log('✅ withLargeHeap: 已启用 largeHeap 模式')
|
||||
|
||||
return config
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = withLargeHeap
|
||||
Loading…
Reference in New Issue