uni-app 真机会崩溃 改进方案用默认图片替代video减少创建数量 只有点击播放时v-if创建video 但列表点击多次翻页后仍崩溃
uni-app 真机会崩溃 改进方案用默认图片替代video减少创建数量 只有点击播放时v-if创建video 但列表点击多次翻页后仍崩溃
bug描述:
nview video下来超过300个后,真机会崩溃,后来改进了方案,用默认图片替代video,这样可以少创建几个video,只有点击播放的时候才会v-if创建video,但是列表点几个翻两页还是会崩溃。
崩溃日志:
Incident Identifier: 9523DF7B-16F6-40A7-960A-1249C9FC33BC
CrashReporter Key: 0b453ce98e2aaeb6ead8927234ae298e602366ce
Hardware Model: iPhone10,1
Process: HBuilder [69752]
Path: /private/var/containers/Bundle/Application/644F8867-BD2A-4B38-B7F1-34B5209B7A19/HBuilder.app/HBuilder
Identifier: io.dcloud.HBuilder
Version: 13.3.13 (130313)
Code Type: ARM-64 (Native)
Role: Foreground
Parent Process: launchd [1]
Coalition: io.dcloud.HBuilder [6870]
Date/Time: 2022-04-12 21:23:36.3149 +0800
Launch Time: 2022-04-12 21:22:44.7563 +0800
OS Version: iPhone OS 15.4 (19E241)
Release Type: User
Baseband Version: 7.02.00
Report Version: 104
Exception Type: EXC_BREAKPOINT (SIGTRAP)
Exception Codes: 0x0000000000000001, 0x00000001926752a8
Exception Note: EXC_CORPSE_NOTIFY
Termination Reason: SIGNAL; [5]
Terminating Process: exc handler [69752]
Terminating Process: exc handler [69752]
Triggered by Thread: 7
...
Binary Images:
0x198d0a000 - 0x198d41fff libobjc.A.dylib arm64 <ce5424bcae9938769e376202060c145b> /usr/lib/libobjc.A.dylib
0x183884000 - 0x18501dfff UIKitCore arm64 <9766f1340b1c34a8a8c9f8cca8978fde> /System/Library/PrivateFrameworks/UIKitCore.framework/UIKitCore
0x181551000 - 0x18198dfff CoreFoundation arm64 <a448b016adb238758ad572e6635def1c> /System/Library/Frameworks/CoreFoundation.framework/CoreFoundation
0x1a1f88000 - 0x1a1f90fff GraphicsServices arm64 <41ace28d19a43850a2f12bd9d6f5b9dd> /System/Library/PrivateFrameworks/GraphicsServices.framework/GraphicsServices
0x102ab4000 - 0x104d67fff HBuilder arm64 <f21d4dd0b11530a9b4fcd6d53ddd8ca1> /private/var/containers/Bundle/Application/644F8867-BD2A-4B38-B7F1-34B5209B7A19/HBuilder.app/HBuilder
0x105cac000 - 0x105cfffff dyld arm64 <5c4972a8ef8132dca84842cc7f7874cf> /usr/lib/dyld
0x1dc6da000 - 0x1dc6eafff libsystem_pthread.dylib arm64 <7e417a0765333ee7b0de623b5fb464fd> /usr/lib/system/libsystem_pthread.dylib
0x1bbd2c000 - 0x1bbd5ffff libsystem_kernel.dylib arm64 <3d3637098d2d3d1e8cab11d232e5d508> /usr/lib/system/libsystem_kernel.dylib
0x182c60000 - 0x182f43fff Foundation arm64 <7482ad1b76ee38b48dac0960f9f9521e> /System/Library/Frameworks/Foundation.framework/Foundation
0x181d2c000 - 0x1821bcfff CFNetwork arm64 <0db401d13f6d349ca893ebd36ec7d9a0> /System/Library/Frameworks/CFNetwork.framework/CFNetwork
0x18bd57000 - 0x18cf9efff JavaScriptCore arm64 <95f30dd41bdb3dcaa5c2ec2e563168ab> /System/Library/Frameworks/JavaScriptCore.framework/JavaScriptCore
0x19266d000 - 0x19270cfff FrontBoardServices arm64 <c64f9bc0e1ac339b86a5d858bf30cd45> /System/Library/PrivateFrameworks/FrontBoardServices.framework/FrontBoardServices
0x1dc654000 - 0x1dc655fff libsystem_blocks.dylib arm64 <70089b1ce6d234a5b3a7909a6bd1b274> /usr/lib/system/libsystem_blocks.dylib
0x18bc88000 - 0x18bd03fff libsystem_c.dylib arm64 <0c058d0be8f036aa9766fa72ee100d98> /usr/lib/system/libsystem_c.dylib
0x18a2f0000 - 0x18a318fff AudioSession arm64 <76cba8eb346c3ba5a1464575c7243cb2> /System/Library/PrivateFrameworks/AudioSession.framework/AudioSession
0x18dcc0000 - 0x18dfb6fff CoreMotion arm64 <c49e1372aad83e1f995c46f448121b71> /System/Library/Frameworks/CoreMotion.framework/CoreMotion
0x18b801000 - 0x18ba7efff AudioToolbox arm64 <440cb628964235b1b7e09d980670008f> /System/Library/Frameworks/AudioToolbox.framework/AudioToolbox
0x19963f000 - 0x19966ffff libAudioToolboxUtility.dylib arm64 <8566ddbb927d35c9b4ccb0156dc81e99> /usr/lib/libAudioToolboxUtility.dylib
0x181240000 - 0x1812c2fff libdispatch.dylib arm64 <f14f0161e0de3d9c851ead12f95a3073> /usr/lib/system/libdispatch.dylib
0x1dda01000 - 0x1ddb66fff AGXMetalA11 arm64 <a097180fff3532afab5e2b3591f5b60a> /System/Library/Extensions/AGXMetalA11.bundle/AGXMetalA11
0x1dcc47000 - 0x1dcc64fff AppleMetalGLRenderer arm64 <82680b65145e3e62b4966bdcccec66f1> /System/Library/Extensions/AppleMetalGLRenderer.bundle/AppleMetalGLRenderer
0x1c241c000 - 0x1c24e4fff GLEngine arm64 <facc8b4189fa38b2a986884500775b7d> /System/Library/Frameworks/OpenGLES.framework/GLEngine.bundle/GLEngine
0x1c24e5000 - 0x1c24eefff OpenGLES arm64 <d5124e1ecc7e38d6801da81f33374b46> /System/Library/Frameworks/OpenGLES.framework/OpenGLES
3 回复
我在你 上个帖子 回复了啊 试试 recycle-list
https://uniapp.dcloud.net.cn/component/recycle-list.html
好的 感谢
在 uni-app
中,使用 video
组件时,如果列表中有大量视频,可能会导致内存占用过高,进而导致应用崩溃。你提到的方案(使用默认图片替代 video
,只有在点击播放时通过 v-if
创建 video
)是一个很好的优化思路,但如果多次翻页后仍然崩溃,可能是由于以下原因:
- 内存泄漏:即使通过
v-if
销毁了video
组件,可能仍然存在内存泄漏问题,导致内存占用不断增加。 - 视频资源未释放:即使
video
组件被销毁,视频资源可能没有被完全释放。 - 列表数据过多:如果列表数据过多,即使每次只渲染少量
video
,随着翻页次数的增加,内存占用仍然会累积。
改进方案
1. 使用 v-if
和 v-show
结合
- 使用
v-if
来动态创建和销毁video
组件,确保只有当前播放的视频才会被渲染。 - 使用
v-show
来控制默认图片的显示和隐藏,避免频繁创建和销毁 DOM 元素。
<template>
<div v-for="(item, index) in videoList" :key="index">
<div v-show="!item.isPlaying" @click="playVideo(item, index)">
<img :src="item.poster" alt="video-poster" />
</div>
<video v-if="item.isPlaying" :src="item.src" controls @ended="onVideoEnded(item, index)"></video>
</div>
</template>
<script>
export default {
data() {
return {
videoList: [
{ src: 'video1.mp4', poster: 'poster1.jpg', isPlaying: false },
{ src: 'video2.mp4', poster: 'poster2.jpg', isPlaying: false },
// 更多视频数据
],
};
},
methods: {
playVideo(item, index) {
// 停止其他正在播放的视频
this.videoList.forEach((video, i) => {
if (i !== index) {
video.isPlaying = false;
}
});
// 播放当前视频
item.isPlaying = true;
},
onVideoEnded(item, index) {
item.isPlaying = false;
},
},
};
</script>
2. 手动释放视频资源
在 video
组件销毁时,手动释放视频资源,确保内存被正确回收。
methods: {
playVideo(item, index) {
// 停止其他正在播放的视频
this.videoList.forEach((video, i) => {
if (i !== index && video.isPlaying) {
video.isPlaying = false;
this.$refs[`video${i}`][0].pause(); // 暂停视频
this.$refs[`video${i}`][0].src = ''; // 清空视频源
}
});
// 播放当前视频
item.isPlaying = true;
},
onVideoEnded(item, index) {
item.isPlaying = false;
this.$refs[`video${index}`][0].src = ''; // 清空视频源
},
},
3. 分页加载
如果列表数据过多,可以考虑分页加载,每次只加载当前页的数据,减少内存占用。
methods: {
loadMore() {
// 加载更多数据
this.videoList = this.videoList.concat(newVideoList);
},
},
4. 使用 IntersectionObserver
懒加载
使用 IntersectionObserver
来监听 video
组件是否进入视口,只有在进入视口时才加载视频资源。
mounted() {
this.observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const index = entry.target.dataset.index;
this.videoList[index].isPlaying = true;
this.observer.unobserve(entry.target);
}
});
});
this.$nextTick(() => {
this.$refs.videoList.forEach((video, index) => {
this.observer.observe(video);
});
});
},
beforeDestroy() {
this.observer.disconnect();
},