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)是一个很好的优化思路,但如果多次翻页后仍然崩溃,可能是由于以下原因:

  1. 内存泄漏:即使通过 v-if 销毁了 video 组件,可能仍然存在内存泄漏问题,导致内存占用不断增加。
  2. 视频资源未释放:即使 video 组件被销毁,视频资源可能没有被完全释放。
  3. 列表数据过多:如果列表数据过多,即使每次只渲染少量 video,随着翻页次数的增加,内存占用仍然会累积。

改进方案

1. 使用 v-ifv-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();
},
回到顶部
AI 助手
你好,我是IT营的 AI 助手
您可以尝试点击下方的快捷入口开启体验!