package com.xscm.moduleutil.widget; import android.content.Context; import android.opengl.GLSurfaceView; import android.os.Handler; import android.os.Looper; import android.util.AttributeSet; import android.util.Log; import android.view.LayoutInflater; import android.view.SoundEffectConstants; import android.view.View; import android.widget.FrameLayout; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.databinding.DataBindingUtil; import com.blankj.utilcode.util.LogUtils; import com.liulishuo.okdownload.DownloadTask; import com.liulishuo.okdownload.core.cause.EndCause; import com.liulishuo.okdownload.core.cause.ResumeFailedCause; import com.liulishuo.okdownload.core.listener.DownloadListener1; import com.liulishuo.okdownload.core.listener.assist.Listener1Assist; import com.opensource.svgaplayer.SVGACallback; import com.opensource.svgaplayer.SVGADrawable; import com.opensource.svgaplayer.SVGADynamicEntity; import com.opensource.svgaplayer.SVGAImageView; import com.opensource.svgaplayer.SVGAParser; import com.opensource.svgaplayer.SVGAVideoEntity; import com.tencent.qgame.animplayer.inter.IAnimListener; import com.xscm.moduleutil.R; import com.xscm.moduleutil.databinding.RoomViewSvgaAnimBinding; import com.xscm.moduleutil.utils.SpUtil; import com.xscm.moduleutil.utils.logger.Logger; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.lang.ref.WeakReference; import java.net.URL; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.Map; import java.util.Queue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import okhttp3.Call; import okhttp3.Callback; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; import okhttp3.ResponseBody; public class AvatarFrameView extends FrameLayout { private PlaybackManager playbackManager; private boolean isMute = false; public void setMute(boolean b) { this.isMute = b; } public enum RenderType {SVGA, MP4} private RenderType renderType; private SVGAImageView svgaSurface; private SVGAImageView svgaSurface2; private final Handler mainHandler = new Handler(Looper.getMainLooper()); private int mType;//1:循环播放 2:播放一次停止播放 private final BlockingQueue playQueue = new LinkedBlockingQueue<>(); private boolean isPlaying = false; // 添加销毁标记 private boolean isDestroyed = false; private static final String TAG = "AvatarFrameView"; private RoomViewSvgaAnimBinding mBinding; // 内存监控 private static final long MAX_MEMORY_THRESHOLD = 300 * 1024 * 1024; // 300MB private static final int MAX_SVGA_CACHE_SIZE = 3; private final Map> svgaCache = new LruCache<>(MAX_SVGA_CACHE_SIZE); public AvatarFrameView(@NonNull Context context) { this(context, null); } public AvatarFrameView(@NonNull Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public AvatarFrameView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mBinding = DataBindingUtil.inflate(LayoutInflater.from(context), R.layout.room_view_svga_anim, this, true); initViews(); } private void initViews() { // if (isDestroyed) return; // 初始化 ExoPlayer View // playerView = new PlayerView(getContext()); // playerView.setUseController(false); // playerView.setVisibility(View.GONE); // addView(playerView); // 初始化 SVGA View svgaSurface = new SVGAImageView(getContext()); svgaSurface.setVisibility(View.GONE); addView(svgaSurface); svgaSurface2 = new SVGAImageView(getContext()); svgaSurface2.setVisibility(View.GONE); addView(svgaSurface2); // 初始化播放管理器 playbackManager = new PlaybackManager(mainHandler); } private String getFileExtension(String url) { if (url == null || url.isEmpty()) return ""; int dotIndex = url.lastIndexOf("."); if (dotIndex > 0 && dotIndex < url.length() - 1) { return url.substring(dotIndex + 1).toLowerCase(); // 返回 "mp4", "svga" 等 } return ""; } public void playNextFromQueue() { // if (isDestroyed) return; // 确保在主线程中执行 // if (Looper.myLooper() != Looper.getMainLooper()) { // mainHandler.post(this::playNextFromQueue); // return; // } // 检查特效是否开启 // if (SpUtil.getOpenEffect() != 1) { // clearQueue(); // return; // } // 检查是否可以开始新的播放 // if (!playbackManager.canStartNewPlayback()) { // Logger.d("AvatarFrameView", "Max concurrent playbacks reached, waiting..."); // return; // } if (!isPlaying || !isActuallyPlaying()) { PlayItem item = playQueue.poll(); if (item != null) { // 通知开始播放 playbackManager.onStartPlayback(); isPlaying = true; // 处理播放项目 processPlayItem(item); } else { isPlaying = false; Logger.d("AvatarFrameView", "Queue is empty, stop playing"); } } } // 添加统一的播放完成处理方法 public void onPlaybackComplete() { if (isDestroyed) return; mainHandler.post(() -> { // 再次检查是否已销毁 if (isDestroyed) return; // // 通知播放管理器播放完成 // playbackManager.onFinishPlayback(); // 重置播放状态 isPlaying = false; // 内存清理检查 // if (playQueue.size() % 5 == 0) { // performLightMemoryCleanup(); // } // 继续处理队列中的下一个项目 playNextFromQueue(); }); } private void processPlayItem(PlayItem item) { try { // clearPrevious(); String ext = getFileExtension(item.url); if ("svga".equalsIgnoreCase(ext)) { mainHandler.post(() -> { renderType = RenderType.SVGA; mType = item.type; if (mBinding != null && mBinding.playView != null) { mBinding.playView.setVisibility(View.GONE); } loadSVGA(item.url); }); } else if ("mp4".equalsIgnoreCase(ext)) { mainHandler.post(() -> { renderType = RenderType.MP4; mType = item.type; if (mBinding != null && mBinding.playView != null) { mBinding.playView.setVisibility(View.VISIBLE); downloadAndPlayMp4(item.url); }else { mBinding = DataBindingUtil.inflate(LayoutInflater.from(getContext()), R.layout.room_view_svga_anim, this, true); mBinding.playView.setVisibility(View.VISIBLE); downloadAndPlayMp4(item.url); } }); } else { // 不支持的格式,直接完成 handlePlaybackComplete(); } } catch (Exception e) { LogUtils.e(TAG, "Error processing play item: " + e.getMessage()); handlePlaybackComplete(); } } // 添加实际播放状态检查方法 private boolean isActuallyPlaying() { if (renderType == RenderType.SVGA && svgaSurface != null) { return svgaSurface.isAnimating(); } else if (renderType == RenderType.MP4 && mBinding != null) { // 检查播放器状态 return mBinding.playView.isRunning(); } return false; } public boolean isPlaying() { if (mBinding != null && mBinding.playView != null) { return mBinding.playView.isRunning(); } return true; } // 在 AvatarFrameView 类中添加以下代码 private static final int MAX_CONCURRENT_PROCESSING = 3; // 同时处理的最大动画数 private static final int PROCESSING_DELAY = 100; // 处理间隔(毫秒) private int currentProcessingCount = 0; public void setSource(String url, int type2) { // if (isDestroyed) return; // 确保在主线程中执行 if (Looper.myLooper() != Looper.getMainLooper()) { mainHandler.post(() -> setSource(url, type2)); return; } // 添加到播放队列 playQueue.add(new PlayItem(url, type2)); Logger.d("AvatarFrameView", "Added to queue, queue size: " + playQueue.size() + ", url: " + url); if (type2 == 3 || type2 == 1) { // playNextFromQueue(); loadSVGA(url); } else { // 如果当前没有在播放,则开始播放 if (!isPlaying || !isActuallyPlaying()) { playNextFromQueue(); } } Logger.d("AvatarFrameView", "Added to queue, queue size: " + playQueue.size() + ", url: " + url); } private void smartCheckAndStartPlayback() { // 检查是否可以开始新的播放任务 if (!playQueue.isEmpty() && (!isPlaying || !isActuallyPlaying()) && currentProcessingCount < MAX_CONCURRENT_PROCESSING) { currentProcessingCount++; playNextFromQueue(); } } private void checkAndStartPlayback() { // 如果队列不为空且当前没有在播放,则开始播放 if (!playQueue.isEmpty() && (!isPlaying || !isActuallyPlaying())) { playNextFromQueue(); } } private boolean isMemoryLow() { Runtime runtime = Runtime.getRuntime(); long usedMemory = runtime.totalMemory() - runtime.freeMemory(); long maxMemory = runtime.maxMemory(); double memoryUsage = (double) usedMemory / maxMemory; // 内存使用超过80%或绝对使用量超过阈值 return memoryUsage > 0.8 || usedMemory > MAX_MEMORY_THRESHOLD; } boolean isTxk = false; public void downloadAndPlayMp4(String url) { // 提取文件名 String fileName = url.substring(url.lastIndexOf("/")); String filePath = getContext().getCacheDir().getAbsolutePath() + fileName; LogUtils.e("@@@@@filePath: " + filePath.toString()); File file = new File(filePath); if (!file.exists()) { LogUtils.e("无缓存"); // 使用OkHttp进行下载 OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder() .url(url) .build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { LogUtils.e("MP4下载失败: " + e.toString()); mainHandler.post(() -> { // 检查是否已销毁 if (!isDestroyed) { onPlaybackComplete(); } }); } // 更简单的优化版本 @Override public void onResponse(Call call, Response response) throws IOException { // 在异步回调中首先检查是否已销毁 if (isDestroyed) { LogUtils.w(TAG, "View destroyed before download completed"); return; } LogUtils.d("@@@@", "onResponse" + Thread.currentThread().getName()); if (response.isSuccessful()) { try (ResponseBody responseBody = response.body()) { if (responseBody != null) { // 在后台线程处理文件保存 String fileName = url.substring(url.lastIndexOf("/")); String filePath = getContext().getCacheDir().getAbsolutePath() + fileName; File downloadedFile = new File(filePath); // 使用流式传输避免大文件卡顿 try (InputStream inputStream = responseBody.byteStream(); FileOutputStream fos = new FileOutputStream(downloadedFile)) { // 定义缓冲区大小(8KB) byte[] buffer = new byte[1024 * 1024]; int bytesRead; // 流式读取并写入文件 while ((bytesRead = inputStream.read(buffer)) != -1) { fos.write(buffer, 0, bytesRead); } fos.flush(); isTxk = true; mainHandler.post(() -> { // 关键:在执行UI操作前再次检查是否已销毁 if (downloadedFile.exists()) { LogUtils.d("@@@@Thread", Thread.currentThread().getName()); playMp4File(downloadedFile); // 使用正确的文件引用 } else { LogUtils.w(TAG, "View destroyed or file not exist after download"); onPlaybackComplete(); } }); } catch (IOException e) { LogUtils.e("MP4文件保存失败: " + e.getMessage()); mainHandler.post(() -> { if (!isDestroyed) { onPlaybackComplete(); } }); } } else { mainHandler.post(() -> { if (!isDestroyed) { onPlaybackComplete(); } }); } } catch (Exception e) { LogUtils.e("MP4文件保存失败: " + e.getMessage()); mainHandler.post(() -> { if (!isDestroyed) { onPlaybackComplete(); } }); } } else { LogUtils.e("MP4下载响应失败"); mainHandler.post(() -> { if (!isDestroyed) { onPlaybackComplete(); } }); } } }); } else { isTxk = true; LogUtils.e("有缓存"); mainHandler.post(() -> { // 检查是否已销毁 if (file.exists()) { playMp4File(file); } else { LogUtils.w(TAG, "有缓存2222222222222"); } }); } } private void playMp4File(File file) { try { // 双重检查确保组件未被销毁 if (isDestroyed) { LogUtils.w(TAG, "Attempt to play MP4 file after view destroyed"); onPlaybackComplete(); return; } if (mBinding == null || mBinding.playView == null) { LogUtils.w(TAG, "PlayView is null"); onPlaybackComplete(); return; } if (file != null && file.exists()) { // 设置循环次数(根据mType决定) if (mType == 1 || mType == 3) { mBinding.playView.setLoop(Integer.max(1, 999999999)); // 无限循环 } else { mBinding.playView.setLoop(1); // 播放一次 } mBinding.playView.setMute(isMute); // 开始播放前检查视图状态 if (!isDestroyed && mBinding != null && mBinding.playView != null) { mBinding.playView.startPlay(file); } else { LogUtils.w(TAG, "View was destroyed before MP4 playback started"); onPlaybackComplete(); } } else { LogUtils.e("播放MP4文件出错: 文件不存在或已损坏"); onPlaybackComplete(); } } catch (Exception e) { LogUtils.e("播放MP4文件出错: " + e.getMessage()); onPlaybackComplete(); } } private void handleSVGAComplete(SVGAVideoEntity videoItem, String url) { if (svgaSurface == null) { onPlaybackComplete(); return; } try { // 缓存实体(使用弱引用) if (svgaCache.size() < MAX_SVGA_CACHE_SIZE) { svgaCache.put(url, new WeakReference<>(videoItem)); } SVGADrawable drawable = new SVGADrawable(videoItem, new SVGADynamicEntity()); svgaSurface.setImageDrawable(drawable); svgaSurface.setCallback(new SVGACallback() { @Override public void onStep(int i, double v) { } @Override public void onRepeat() { // 循环播放处理 if (mType != 1) { // 非循环播放 svgaSurface.stopAnimation(); svgaSurface.clearAnimation(); svgaSurface.setImageDrawable(null); onPlaybackComplete(); } } @Override public void onPause() { } @Override public void onFinished() { // if (isDestroyed) return; if (mType == 1) { // 循环播放 // 继续循环播放 } else { onPlaybackComplete(); } } }); // 设置循环次数 if (mType == 1 || mType == 3) { svgaSurface.setLoops(0); // 无限循环 } else { svgaSurface.setLoops(1); // 播放一次 } svgaSurface.startAnimation(); } catch (Exception e) { LogUtils.e(TAG, "Error handling SVGA completion: " + e.getMessage()); // isPlaying = false; // playNextFromQueue(); handlePlaybackComplete(); } } public void stopAll() { if (svgaSurface != null) { svgaSurface.stopAnimation(); svgaSurface.clearAnimation(); svgaSurface.setImageDrawable(null); } if (svgaSurface2 != null) { svgaSurface2.stopAnimation(); svgaSurface2.clearAnimation(); svgaSurface.setImageDrawable(null); } // 增加空值检查 if (mBinding != null && mBinding.playView != null) { mBinding.playView.stopPlay(); } } private void playCachedSVGA(SVGAVideoEntity videoItem) { try { SVGADrawable drawable = new SVGADrawable(videoItem, new SVGADynamicEntity()); svgaSurface.setImageDrawable(drawable); svgaSurface.setCallback(new SVGACallback() { @Override public void onStep(int i, double v) { } @Override public void onRepeat() { } @Override public void onPause() { } @Override public void onFinished() { if (Looper.myLooper() != Looper.getMainLooper()) { mainHandler.post(() -> { isPlaying = false; // 添加延迟确保状态更新 mainHandler.postDelayed(AvatarFrameView.this::playNextFromQueue, 50); }); } else { isPlaying = false; mainHandler.postDelayed(AvatarFrameView.this::playNextFromQueue, 50); } } }); // 设置循环次数 if (mType == 1 || mType == 3) { svgaSurface.setLoops(0); // 无限循环 } else { svgaSurface.setLoops(1); // 播放一次 } svgaSurface.startAnimation(); } catch (Exception e) { LogUtils.e(TAG, "Error playing cached SVGA: " + e.getMessage()); isPlaying = false; mainHandler.postDelayed(AvatarFrameView.this::playNextFromQueue, 50); // playNextFromQueue(); } } private void loadNewSVGA(String url) { try { new SVGAParser(getContext()).parse(new URL(url), new SVGAParser.ParseCompletion() { @Override public void onComplete(SVGAVideoEntity videoItem) { // if (isDestroyed) return; if (Looper.myLooper() != Looper.getMainLooper()) { mainHandler.post(() -> handleSVGAComplete(videoItem, url)); } else { handleSVGAComplete(videoItem, url); } } @Override public void onError() { // if (isDestroyed) return; if (Looper.myLooper() != Looper.getMainLooper()) { mainHandler.post(() -> { isPlaying = false; playNextFromQueue(); }); } else { isPlaying = false; playNextFromQueue(); } } }); } catch (Exception e) { LogUtils.e(TAG, "Error parsing SVGA: " + e.getMessage()); isPlaying = false; playNextFromQueue(); } } private void loadSVGA(String url) { if (Looper.myLooper() != Looper.getMainLooper()) { mainHandler.post(() -> loadSVGA(url)); return; } try { svgaSurface.setVisibility(View.VISIBLE); // 检查缓存 WeakReference cachedRef = svgaCache.get(url); SVGAVideoEntity cachedEntity = cachedRef != null ? cachedRef.get() : null; if (cachedEntity != null) { // 使用缓存的实体 playCachedSVGA(cachedEntity); } else { // 加载新的SVGA loadNewSVGA(url); } } catch (Exception e) { LogUtils.e(TAG, "Error loading SVGA: " + e.getMessage()); isPlaying = false; playNextFromQueue(); } svgaSurface.setVisibility(View.VISIBLE); try { new SVGAParser(getContext()).parse(new URL(url), new SVGAParser.ParseCompletion() { @Override public void onComplete(SVGAVideoEntity videoItem) { SVGADrawable drawable = new SVGADrawable(videoItem, new SVGADynamicEntity()); svgaSurface.setImageDrawable(drawable); svgaSurface.setCallback(new SVGACallback() { @Override public void onStep(int i, double v) { } @Override public void onRepeat() { } @Override public void onPause() { } @Override public void onFinished() { isPlaying = false; playNextFromQueue(); } }); svgaSurface.startAnimation(); } @Override public void onError() { isPlaying = false; playNextFromQueue(); } }); } catch (Exception e) { e.printStackTrace(); } } private void clearPrevious() { try { // 停止并清理 SVGA 动画 if (svgaSurface != null && svgaSurface.getDrawable() instanceof SVGADrawable) { SVGADrawable drawable = (SVGADrawable) svgaSurface.getDrawable(); if (drawable != null) { drawable.stop(); // 清理 SVGADrawable 中的资源 svgaSurface.clearAnimation(); svgaSurface.setImageDrawable(null); } } // 隐藏所有视图 // if (playerView != null) playerView.setVisibility(View.GONE); if (svgaSurface != null) svgaSurface.setVisibility(View.GONE); // 停止播放器 if (mBinding != null && mBinding.playView != null) { mBinding.playView.stopPlay(); mBinding.playView.setVisibility(View.GONE); } } catch (Exception e) { LogUtils.e(TAG, "Error in clearPrevious: " + e.getMessage()); } } // 简单的 LRU Cache 实现 private static class LruCache extends LinkedHashMap { private final int maxSize; public LruCache(int maxSize) { super(16, 0.75f, true); this.maxSize = maxSize; } @Override protected boolean removeEldestEntry(Entry eldest) { return size() > maxSize; } } /** * 释放所有资源 */ private void releaseResources() { LogUtils.d(TAG, "Releasing all resources"); // if (isDestroyed) return; // 使用异步线程处理耗时操作 new Thread(() -> { try { // 在后台线程处理文件操作和大对象清理 // performHeavyCleanup(); // 回到主线程处理 UI 相关的清理 mainHandler.post(() -> { performUICleanup(); }); } catch (Exception e) { Logger.e(TAG, "Error in async releaseResources: " + e.getMessage()); // 出错时仍在主线程清理 UI 资源 mainHandler.post(() -> { performUICleanup(); }); } }).start(); } /** * 在后台线程执行耗时的清理操作 */ private void performHeavyCleanup() { try { // 清理缓存文件(如果需要) // 清理大对象引用等 // clearCacheFiles(); } catch (Exception e) { Logger.e(TAG, "Error in performHeavyCleanup: " + e.getMessage()); } } /** * 在主线程执行 UI 相关的清理操作 */ private void performUICleanup() { try { // 停止并清理播放器 if (mBinding != null && mBinding.playView != null) { try { mBinding.playView.stopPlay(); } catch (Exception e) { Logger.e(TAG, "Error stopping playView: " + e.getMessage()); } } // 清理 ExoPlayer 资源 // if (exoPlayer != null) { // try { // // 使用异步停止避免阻塞 // exoPlayer.stop(); // exoPlayer.clearVideoSurface(); // } catch (Exception e) { // Logger.e(TAG, "Error releasing ExoPlayer resources: " + e.getMessage()); // } // } // 清理 SVGA 资源 if (svgaSurface != null) { try { // svgaSurface.pauseAnimation(); // svgaSurface.clearAnimation(); // svgaSurface.setImageDrawable(null); svgaSurface.stopAnimation(true); svgaSurface.clear(); svgaSurface.clearAnimation(); svgaSurface.setImageDrawable(null); } catch (Exception e) { Logger.e(TAG, "Error releasing SVGA resources: " + e.getMessage()); } } } catch (Exception e) { Logger.e(TAG, "Error in performUICleanup: " + e.getMessage()); } } /** * 公共释放方法,用于外部主动释放资源 */ public void release() { Logger.d("AvatarFrameView", "Public release called"); // if (isDestroyed) return; // 确保在主线程中执行 // if (Looper.myLooper() != Looper.getMainLooper()) { // mainHandler.post(this::release); // return; // } isDestroyed = true; try { // 清空播放队列 clearQueue(); // 清理播放管理器 if (playbackManager != null) { playbackManager.reset(); } // 释放所有资源 releaseResources(); // 延迟清理其他资源 mainHandler.postDelayed(() -> { // 清理 binding if (mBinding != null) { mBinding = null; } }, 100); // 清理 binding if (mBinding != null) { mBinding = null; } } catch (Exception e) { LogUtils.e(TAG, "Error in AvatarFrameView release: " + e.getMessage()); } finally { // 建议进行垃圾回收 // MemoryOptimizationUtils.forceGC(); } } public void clearQueue() { // if (isDestroyed) return; playQueue.clear(); isPlaying = false; // 清理播放管理器中的任务 if (playbackManager != null) { playbackManager.reset(); } // 清理当前正在播放的内容 clearPrevious(); } // 在类成员变量中添加 private static final int PLAYBACK_TIMEOUT = 10000; // 10秒超时 private Map playbackStartTimeMap = new HashMap<>(); // 添加超时检查方法 private void startPlaybackTimeout(String url) { playbackStartTimeMap.put(url, System.currentTimeMillis()); mainHandler.postDelayed(() -> checkPlaybackTimeout(url), PLAYBACK_TIMEOUT); } private void checkPlaybackTimeout(String url) { Long startTime = playbackStartTimeMap.get(url); if (startTime != null && System.currentTimeMillis() - startTime > PLAYBACK_TIMEOUT) { LogUtils.w(TAG, "Playback timeout: " + url); playbackStartTimeMap.remove(url); // 强制结束当前播放并继续下一个 handlePlaybackComplete(); } } private void cancelPlaybackTimeout(String url) { playbackStartTimeMap.remove(url); } private static class PlayItem { String url; int type; PlayItem(String url, int type) { this.url = url; this.type = type; } } /** * 关闭特效 */ public void closeEffect() { // 清空队列 clearQueue(); // 释放资源 // releaseResources(); // 清空队列 // playQueue.clear(); // 关闭动画 // if (mBinding.playView != null && isPlaying && mBinding.playView.isRunning()) { // mBinding.playView.setAnimation(null); // mBinding.playView.clearAnimation(); // mBinding.playView.stopPlay(); // } } /** * 开始循环播放SVGA动画 */ public void startLoopingSvga(String assetName) { if (Looper.myLooper() != Looper.getMainLooper()) { mainHandler.post(() -> startLoopingSvga(assetName)); return; } try { // clearPrevious(); // 清除之前的动画 svgaSurface.setVisibility(View.VISIBLE); new SVGAParser(getContext()).decodeFromAssets(assetName, new SVGAParser.ParseCompletion() { @Override public void onComplete(SVGAVideoEntity svgaVideoEntity) { SVGADrawable drawable = new SVGADrawable(svgaVideoEntity); svgaSurface.setImageDrawable(drawable); svgaSurface.setLoops(0); // 0表示无限循环 svgaSurface.startAnimation(); } @Override public void onError() { Log.e(TAG, "解析SVGA文件失败: " + assetName); } }); } catch (Exception e) { Log.e(TAG, "播放SVGA动画出错", e); } } /** * 停止并销毁当前SVGA动画 */ public void stopSvga() { if (Looper.myLooper() != Looper.getMainLooper()) { mainHandler.post(() -> stopSvga()); return; } try { if (svgaSurface2 != null) { svgaSurface2.stopAnimation(true); svgaSurface2.setImageDrawable(null); svgaSurface2.setVisibility(View.GONE); } } catch (Exception e) { Log.e(TAG, "停止SVGA动画出错", e); } } // 在 AvatarFrameView 类中添加以下代码 // 播放任务管理器 // 替换现有的 PlaybackManager 类 private static class PlaybackManager { private static final int MAX_CONCURRENT_PLAYBACKS = 3; // 增加并发数 private int currentPlaybackCount = 0; private final Handler handler; public PlaybackManager(Handler handler) { this.handler = handler; } public boolean canStartNewPlayback() { return currentPlaybackCount < MAX_CONCURRENT_PLAYBACKS; } public void onStartPlayback() { currentPlaybackCount++; } public void onFinishPlayback() { currentPlaybackCount = Math.max(0, currentPlaybackCount - 1); } public void reset() { currentPlaybackCount = 0; } } // 播放任务接口 private interface PlaybackTask { void execute(); } // 在 AvatarFrameView 类中添加以下代码 // private IAnimListener MP4PlaybackCallback; // 在 AvatarFrameView 类的成员变量区域添加单例实例 public void setAnimListener(IAnimListener mInstance) { mBinding.playView.setAnimListener(mInstance); } // 添加统一的播放完成处理方法 private void handlePlaybackComplete() { mainHandler.post(() -> { if (isDestroyed) return; isPlaying = false; // 通知播放管理器任务完成 if (playbackManager != null) { playbackManager.reset(); } // 内存检查 if (playQueue.size() % 5 == 0) { // performLightMemoryCleanup(); } // 播放下一个 playNextFromQueue(); }); } // 添加轻量级内存清理方法 private void performLightMemoryCleanup() { Runtime runtime = Runtime.getRuntime(); long usedMemory = runtime.totalMemory() - runtime.freeMemory(); long maxMemory = runtime.maxMemory(); double memoryUsage = (double) usedMemory / maxMemory; // 内存使用超过70%时进行清理 if (memoryUsage > 0.7) { // 清理SVGA缓存 if (svgaCache.size() > 1) { // 保留最新的缓存项 Iterator>> iterator = svgaCache.entrySet().iterator(); if (iterator.hasNext()) { iterator.next(); // 跳过最新的 if (iterator.hasNext()) { iterator.remove(); // 移除较旧的 } } } // 建议进行垃圾回收 System.gc(); } } }