Files
midi-android/moduleUtil/src/main/java/com/xscm/moduleutil/widget/AvatarFrameView.java

957 lines
33 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.xscm.moduleutil.widget;
import android.content.Context;
import android.graphics.SurfaceTexture;
import android.net.Uri;
import android.opengl.GLES11Ext;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.os.Handler;
import android.os.Looper;
import android.util.AttributeSet;
import android.util.Log;
import android.util.LruCache;
import android.view.LayoutInflater;
import android.view.Surface;
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.blankj.utilcode.util.PathUtils;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.ui.PlayerView;
import com.liulishuo.okdownload.DownloadTask;
import com.liulishuo.okdownload.StatusUtil;
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.AnimConfig;
import com.tencent.qgame.animplayer.inter.IAnimListener;
import com.tencent.qgame.animplayer.inter.IFetchResource;
import com.xscm.moduleutil.R;
import com.xscm.moduleutil.databinding.RoomViewSvgaAnimBinding;
import com.xscm.moduleutil.utils.Md5Utils;
import com.xscm.moduleutil.utils.MemoryOptimizationUtils;
import com.xscm.moduleutil.utils.SpUtil;
import com.xscm.moduleutil.utils.logger.Logger;
import java.io.File;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.net.URL;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;
public class AvatarFrameView extends FrameLayout implements IAnimListener {
@Override
public void onFailed(int i, @Nullable String s) {
}
@Override
public boolean onVideoConfigReady(@NonNull AnimConfig animConfig) {
return true;
}
@Override
public void onVideoStart() {
}
@Override
public void onVideoRender(int i, @Nullable AnimConfig animConfig) {
}
@Override
public void onVideoComplete() {
// if (mType == 1) {
// mBinding.playView.startPlay(mFile); // 循环播放
// } else {
// isPlaying = false;
// playNextFromQueue(); // 播放下一项
// }
// if (isDestroyed) return;
// 确保在主线程中执行
if (Looper.myLooper() == Looper.getMainLooper()) {
handleVideoComplete();
} else {
mainHandler.post(() -> {
// if (!isDestroyed) {
handleVideoComplete();
// }
});
}
}
private void handleVideoComplete() {
// if (isDestroyed) return;
if (mType == 1) {
if (mBinding != null && mFile != null) {
mBinding.playView.startPlay(mFile); // 循环播放
}
} else {
isPlaying = false;
// playNextFromQueue(); // 播放下一项
mainHandler.postDelayed(this::playNextFromQueue, 50);
}
}
@Override
public void onVideoDestroy() {
}
public enum RenderType {SVGA, MP4}
private RenderType renderType;
private ExoPlayer exoPlayer;
private PlayerView playerView;
private SVGAImageView svgaSurface;
private GLSurfaceView glSurfaceView;
private final Handler mainHandler = new Handler(Looper.getMainLooper());
private ChannelSplitRenderer1 renderer;
private int mType;//1:循环播放 2:播放一次停止播放
private File mFile;
private final Queue<PlayItem> playQueue = new LinkedList<>();
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<String, WeakReference<SVGAVideoEntity>> 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);
// // 初始化 GLSurfaceView
// glSurfaceView = new GLSurfaceView(getContext());
// glSurfaceView.setEGLContextClientVersion(2);
// renderer = new ChannelSplitRenderer1();
// glSurfaceView.setRenderer(renderer);
// glSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
// glSurfaceView.setVisibility(View.GONE); // 默认隐藏
// addView(glSurfaceView);
// 初始化 ExoPlayer
// if (!isDestroyed) {
try {
exoPlayer = new ExoPlayer.Builder(getContext()).build();
playerView.setPlayer(exoPlayer);
} catch (Exception e) {
LogUtils.e("AvatarFrameView", "Failed to initialize ExoPlayer: " + e.getMessage());
}
// }
if (mBinding != null) {
mBinding.playView.setAnimListener(this);
}
}
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 "";
}
private void playNextFromQueue() {
// if (isDestroyed) return;
// 确保在主线程中执行
if (Looper.myLooper() != Looper.getMainLooper()) {
mainHandler.post(this::playNextFromQueue);
return;
}
// 再次检查内存状态
// if (isMemoryLow()) {
// LogUtils.w(TAG, "Low memory, clearing queue");
// clearQueue();
// return;
// }
// 检查特效是否开启
if (SpUtil.getOpenEffect() != 1) {
clearQueue();
return;
}
// 关键:即使 isPlaying 为 true也要检查实际播放状态
if (isPlaying && isActuallyPlaying()) {
Logger.d("AvatarFrameView", "Already playing, skip");
return;
}
PlayItem item = playQueue.poll();
if (item != null) {
isPlaying = true;
Logger.d("AvatarFrameView", "Playing item, remaining queue size: " + playQueue.size());
RenderType type = null;
String ext = getFileExtension(item.url);
if ("svga".equalsIgnoreCase(ext)) {
type = RenderType.SVGA;
} else if ("mp4".equalsIgnoreCase(ext)) {
type = RenderType.MP4;
}
if (type == null) {
isPlaying = false;
playNextFromQueue(); // 跳过无效项
return;
}
clearPrevious();
renderType = type;
mType = item.type;
switch (type) {
case SVGA:
mBinding.playView.stopPlay();
mBinding.playView.setVisibility(View.GONE);
loadSVGA(item.url);
break;
case MP4:
mBinding.playView.setVisibility(View.VISIBLE);
downloadAndPlayMp4(item.url);
break;
}
} else {
isPlaying = false;
Logger.d("AvatarFrameView", "Queue is empty, stop playing");
}
}
// 添加实际播放状态检查方法
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 void setSource(String url, int type2) {
// if (isDestroyed) return;
// 确保在主线程中执行
if (Looper.myLooper() != Looper.getMainLooper()) {
mainHandler.post(() -> setSource(url, type2));
return;
}
// // 检查内存状态
// if (isMemoryLow()) {
// LogUtils.w(TAG, "Low memory, skipping animation");
// clearQueue();
// return;
// }
// 检查特效是否开启
if (SpUtil.getOpenEffect() != 1) {
// 特效关闭时清空队列并停止播放
clearQueue();
return;
}
// 添加到播放队列
// playQueue.offer(new PlayItem(url, type2));
playQueue.add(new PlayItem(url, type2));
Logger.d("AvatarFrameView", "Added to queue, queue size: " + playQueue.size() + ", url: " + url);
// 如果当前没有在播放,则开始播放
// if (!isPlaying) {
// playNextFromQueue();
// }
// 改进播放检查逻辑
checkAndStartPlayback();
}
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;
}
// public void setSource(String url, int type2) {
// if (SpUtil.getOpenEffect()==1) {
// playQueue.offer(new PlayItem(url, type2));
// if (!isPlaying) {
// playNextFromQueue();
// }
// }else {
// playQueue.clear();
// isPlaying = false;
// }
//
//// RenderType type = null;
//// if ("svga".equalsIgnoreCase(getFileExtension(url))){
//// type = RenderType.SVGA;
//// }else if ("mp4".equalsIgnoreCase(getFileExtension(url))){
//// type = RenderType.MP4;
//// }
////
//// clearPrevious();
//// renderType = type;
//// mType = type2;
//// switch (type) {
//// case SVGA:
//// mBinding.playView.stopPlay();
//// mBinding.playView.setVisibility(View.GONE);
//// loadSVGA(url);
//// break;
//// case MP4:
////// loadMP4(url);
//// mBinding.playView.setVisibility(View.VISIBLE);
//// downloadAndPlayMp4(url);
//// break;
//// }
// }
private void downloadAndPlayMp4(String url) {
String filePath = PathUtils.getInternalAppCachePath() + Md5Utils.getStringMD5(url) + ".mp4";
File file = new File(filePath);
if (file.exists() && file.length() > 0) {
playMp4(file);
mFile = file;
} else {
// 删除可能存在的损坏文件
// if (file.exists()) {
// file.delete();
// }
DownloadTask task = new DownloadTask.Builder(url, PathUtils.getInternalAppCachePath()
, Md5Utils.getStringMD5(url) + ".mp4")
.setMinIntervalMillisCallbackProcess(300)
.setPassIfAlreadyCompleted(true)
.setAutoCallbackToUIThread(true)
.setConnectionCount(3) // 增加连接数提高稳定性
.setReadBufferSize(1024 * 8) // 增大缓冲区
.build();
if (StatusUtil.isCompleted(task)) {
playMp4(task.getFile());
mFile = task.getFile();
} else if (StatusUtil.isSameTaskPendingOrRunning(task)) {
// 如果任务正在进行中,等待完成
// 可以通过监听器处理
attachToExistingTask(task);
} else {
task.enqueue(new DownloadListener1() {
@Override
public void taskStart(@NonNull DownloadTask task, @NonNull Listener1Assist.Listener1Model model) {
Logger.e("AvatarFrameView1", model);
}
@Override
public void retry(@NonNull DownloadTask task, @NonNull ResumeFailedCause cause) {
Logger.e("AvatarFrameView2", cause);
}
@Override
public void connected(@NonNull DownloadTask task, int blockCount, long currentOffset, long totalLength) {
Logger.e("AvatarFrameView3", blockCount);
}
@Override
public void progress(@NonNull DownloadTask task, long currentOffset, long totalLength) {
Logger.e("AvatarFrameView4", currentOffset);
}
@Override
public void taskEnd(@NonNull DownloadTask task, @NonNull EndCause cause, @Nullable Exception realCause, @NonNull Listener1Assist.Listener1Model model) {
Logger.e("AvatarFrameView5", model);
// playMp4(task.getFile());
// mFile = task.getFile();
// if (cause != null && cause != EndCause.COMPLETED) {
//// CrashReport.postCatchedException(new RuntimeException("下载任务结束:" + cause == null ? "" : cause.name() + "_realCause:" + realCause == null ? "" : realCause.getMessage()));
// }
if (cause == EndCause.COMPLETED) {
File downloadedFile = task.getFile();
if (downloadedFile != null && downloadedFile.exists() && downloadedFile.length() > 0) {
playMp4(downloadedFile);
mFile = downloadedFile;
} else {
Logger.e(TAG, "Downloaded file is invalid");
handleDownloadFailure(url, cause, new IOException("Downloaded file is invalid"));
}
} else {
handleDownloadFailure(url, cause, realCause);
}
}
});
}
}
}
private void handleDownloadFailure(String url, EndCause cause, Exception realCause) {
Logger.e(TAG, "Download failed: " + cause + ", real cause: " + realCause);
// 尝试重试一次
mainHandler.postDelayed(() -> {
// 检查队列是否仍然包含这个项目
boolean shouldRetry = false;
for (PlayItem item : playQueue) {
if (item.url.equals(url)) {
shouldRetry = true;
break;
}
}
if (shouldRetry) {
// 重新添加到队列开头
playQueue.add(new PlayItem(url, mType));
playNextFromQueue();
} else {
isPlaying = false;
playNextFromQueue();
}
}, 1000); // 1秒后重试
}
// 添加检查进行中任务的方法
private void attachToExistingTask(DownloadTask task) {
// 为已经在队列中的任务附加监听器
task.enqueue(new DownloadListener1() {
@Override
public void taskEnd(@NonNull DownloadTask task, @NonNull EndCause cause, @Nullable Exception realCause, @NonNull Listener1Assist.Listener1Model model) {
if (cause == EndCause.COMPLETED) {
playMp4(task.getFile());
mFile = task.getFile();
} else {
isPlaying = false;
playNextFromQueue();
}
}
// 其他回调方法保持空实现或按需处理
@Override public void taskStart(@NonNull DownloadTask task, @NonNull Listener1Assist.Listener1Model model) {}
@Override public void retry(@NonNull DownloadTask task, @NonNull ResumeFailedCause cause) {}
@Override public void connected(@NonNull DownloadTask task, int blockCount, long currentOffset, long totalLength) {}
@Override public void progress(@NonNull DownloadTask task, long currentOffset, long totalLength) {}
});
}
private void playMp4(File file) {
if (file != null) {
mBinding.playView.startPlay(file);
} else {
// showAnim();
// playMp4(file);
// CrashReport.postCatchedException(new RuntimeException("播放MP4失败:File is null"));
}
}
private void handleSVGAComplete(SVGAVideoEntity videoItem, String url) {
// if (isDestroyed || svgaSurface == null) return;
try {
// 缓存实体(使用弱引用)
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() {
}
@Override
public void onPause() {
}
@Override
public void onFinished() {
// if (isDestroyed) return;
if (Looper.myLooper() != Looper.getMainLooper()) {
mainHandler.post(() -> {
isPlaying = false;
playNextFromQueue();
});
} else {
isPlaying = false;
playNextFromQueue();
}
}
});
svgaSurface.startAnimation();
} catch (Exception e) {
LogUtils.e(TAG, "Error handling SVGA completion: " + e.getMessage());
isPlaying = false;
playNextFromQueue();
}
}
private void playCachedSVGA(SVGAVideoEntity videoItem) {
// if (isDestroyed || svgaSurface == null) return;
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 (isDestroyed) return;
if (Looper.myLooper() != Looper.getMainLooper()) {
mainHandler.post(() -> {
isPlaying = false;
// 添加延迟确保状态更新
mainHandler.postDelayed(AvatarFrameView.this::playNextFromQueue, 50);
// playNextFromQueue();
});
} else {
isPlaying = false;
// playNextFromQueue();
mainHandler.postDelayed(AvatarFrameView.this::playNextFromQueue, 50);
}
}
});
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) {
// if (isDestroyed) return;
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 (isDestroyed || svgaSurface == null) return;
if (Looper.myLooper() != Looper.getMainLooper()) {
mainHandler.post(() -> loadSVGA(url));
return;
}
try {
svgaSurface.setVisibility(View.VISIBLE);
// 检查缓存
WeakReference<SVGAVideoEntity> 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.setCallback(new SVGAImageViewCallback() {
// @Override
// public void onAnimationFinished() {
// isPlaying = false;
// playNextFromQueue();
// }
// });
svgaSurface.startAnimation();
}
@Override
public void onError() {
isPlaying = false;
playNextFromQueue();
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
private void loadMP4(String url) {
svgaSurface.setVisibility(View.GONE);
playerView.setVisibility(View.GONE);
glSurfaceView.setVisibility(View.VISIBLE);
glSurfaceView.onResume();
glSurfaceView.requestRender();
// 使用 post 确保 GLSurfaceView 已完成 layout
glSurfaceView.post(() -> {
Log.d("@@@", "GLSurfaceView size after layout: " + glSurfaceView.getWidth() + "x" + glSurfaceView.getHeight());
glSurfaceView.onResume();
glSurfaceView.requestRender();
renderer.setOnSurfaceTextureReadyListener(surfaceTexture -> {
mainHandler.post(() -> {
Surface surface = new Surface(surfaceTexture);
MediaItem mediaItem = MediaItem.fromUri(Uri.parse(url));
exoPlayer.setMediaItem(mediaItem);
exoPlayer.setVideoSurface(surface);
exoPlayer.prepare();
exoPlayer.play();
Log.d("@@@", "ExoPlayer state after play: " + exoPlayer.getPlaybackState());
});
});
});
}
private void clearPrevious() {
// if (isDestroyed) return;
// 确保在主线程中执行
if (Looper.myLooper() != Looper.getMainLooper()) {
mainHandler.post(() -> {
// if (!isDestroyed) {
clearPrevious();
// }
});
return;
}
try {
// 停止并清理 ExoPlayer
if (exoPlayer != null) {
try {
exoPlayer.stop(); // 这里可能会在错误线程中调用
exoPlayer.clearVideoSurface();
} catch (Exception e) {
Logger.e("Error stopping ExoPlayer: " + e.getMessage());
// 如果在错误线程中,切换到主线程重试
mainHandler.post(() -> {
try {
if (exoPlayer != null) {
exoPlayer.stop();
exoPlayer.clearVideoSurface();
}
} catch (Exception ex) {
Logger.e("Error stopping ExoPlayer on main thread: " + ex.getMessage());
}
});
}
}
// 停止并清理 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);
mBinding.playView.setVisibility(View.GONE);
// 停止播放器
if (mBinding.playView != null) {
mBinding.playView.stopPlay();
}
} catch (Exception e) {
LogUtils.e(TAG, "Error in clearPrevious: " + e.getMessage());
}
// if (svgaSurface.getDrawable() instanceof SVGADrawable) {
// ((SVGADrawable) svgaSurface.getDrawable()).stop();
// }
// if (playerView != null) playerView.setVisibility(View.GONE);
// if (svgaSurface != null) svgaSurface.setVisibility(View.GONE);
// if (glSurfaceView != null) glSurfaceView.setVisibility(View.GONE);
// mBinding.playView.setVisibility(View.GONE);
}
// 简单的 LRU Cache 实现
private static class LruCache<K, V> extends LinkedHashMap<K, V> {
private final int maxSize;
public LruCache(int maxSize) {
super(16, 0.75f, true);
this.maxSize = maxSize;
}
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size() > maxSize;
}
}
/**
* 释放所有资源
*/
private void releaseResources() {
LogUtils.d(TAG, "Releasing all resources");
// if (isDestroyed) return;
try {
// 清理 SVGA 资源
if (svgaSurface != null && svgaSurface.getDrawable() instanceof SVGADrawable) {
SVGADrawable drawable = (SVGADrawable) svgaSurface.getDrawable();
if (drawable != null) {
try {
drawable.stop();
svgaSurface.clearAnimation();
svgaSurface.setImageDrawable(null);
} catch (Exception e) {
LogUtils.e(TAG, "Error releasing SVGA resources: " + e.getMessage());
}
}
}
// 停止并清理播放器
if (mBinding != null && mBinding.playView != null) {
mBinding.playView.stopPlay();
}
// 清理 ExoPlayer 资源
if (exoPlayer != null) {
try {
exoPlayer.stop();
exoPlayer.clearVideoSurface();
} catch (Exception e) {
LogUtils.e(TAG, "Error releasing ExoPlayer resources: " + e.getMessage());
}
}
} catch (Exception e) {
LogUtils.e(TAG, "Error in releaseResources: " + 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();
// 释放所有资源
releaseResources();
// 释放 ExoPlayer
if (exoPlayer != null) {
try {
exoPlayer.stop();
exoPlayer.release();
} catch (Exception e) {
LogUtils.e(TAG, "Error releasing ExoPlayer: " + e.getMessage());
}
exoPlayer = null;
}
// 清理 PlayerView
if (playerView != null) {
try {
playerView.setPlayer(null);
} catch (Exception e) {
LogUtils.e(TAG, "Error releasing PlayerView: " + e.getMessage());
}
playerView = null;
}
// 清理 SVGAImageView
if (svgaSurface != null) {
try {
svgaSurface.pauseAnimation();
svgaSurface.clearAnimation();
svgaSurface.setImageDrawable(null);
} catch (Exception e) {
LogUtils.e(TAG, "Error releasing SVGAImageView: " + e.getMessage());
}
svgaSurface = null;
}
// 清理 binding
if (mBinding != null) {
mBinding = null;
}
// 清理队列
playQueue.clear();
} 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;
// 清理当前正在播放的内容
clearPrevious();
}
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.image != null && isPlaying && mBinding.image.isAnimating()) {
// mBinding.image.setAnimation(null);
// mBinding.image.clearAnimation();
// mBinding.image.stopAnimation();
// }
}
}