package com.xscm.moduleutil.widget; import android.content.Context; import android.text.TextUtils; import android.util.AttributeSet; import android.view.View; import android.widget.FrameLayout; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.blankj.utilcode.util.LogUtils; import com.tencent.qgame.animplayer.AnimConfig; import com.tencent.qgame.animplayer.AnimView; import com.tencent.qgame.animplayer.inter.IAnimListener; import com.xscm.moduleutil.bean.GiftBean; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.locks.ReentrantLock; import lombok.Setter; import okhttp3.Call; import okhttp3.Callback; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; import okhttp3.ResponseBody; public class GiftAnimView extends FrameLayout implements GiftSvgaView.OnAnimationListener { private AnimView playerMp4View; private GiftSvgaView svgaView; private GiftBean playModel; private boolean isLoadEffect = false; private boolean isShow = true;//是否开启特效 private ReentrantLock lock = new ReentrantLock(); private List giftArray = new ArrayList<>(); @Setter public ExecutorService queue; private Context mContext; private boolean isOnece; // 添加带Context参数的构造函数 // 添加带Context和AttributeSet参数的构造函数(解决XML inflate问题的关键) public GiftAnimView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); this.mContext = context; init(); } // 添加带Context、AttributeSet和 defStyleAttr 参数的构造函数(更完整的实现) public GiftAnimView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); this.mContext = context; init(); } public GiftAnimView(Context context) { super(context); this.mContext = context; init(); } private void init() { isLoadEffect = false; // setBackgroundColor(getResources().getColor(R.color.colorBlack45)); // 初始化SVGA视图 svgaView = new GiftSvgaView(getContext()); addView(svgaView); playerMp4View = new AnimView(getContext()); addView(playerMp4View); // 设置布局参数 - 在Android中通常使用LayoutParams LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); playerMp4View.setLoop(1); playerMp4View.setLayoutParams(params); playerMp4View.setAnimListener(new IAnimListener() { @Override public void onVideoDestroy() { LogUtils.e("onVideoDestroy"); } @Override public void onVideoComplete() { LogUtils.e("onVideoComplete"); post(() -> { if (playerMp4View!=null) { playerMp4View.setVisibility(View.GONE); if (isOnece){ return; } // 通知播放完成 notifyPlaybackComplete(); loadStartSVGAPlayer(); } }); } @Override public void onVideoRender(int i, @Nullable AnimConfig animConfig) { // LogUtils.e("onVideoRender", i, animConfig); } @Override public void onVideoStart() { LogUtils.e("onVideoStart"); } @Override public boolean onVideoConfigReady(@NonNull AnimConfig animConfig) { LogUtils.e("onVideoConfigReady", animConfig); return true; } @Override public void onFailed(int i, @Nullable String s) { LogUtils.e("onFailed", s); } }); svgaView.setDidFinishedDisplay(this); svgaView.setDidStartAnimation(this); } public void displayEffectView1(List stringList){ queue.execute(new Runnable() { @Override public void run() { /// 如果play_image不存在return if (stringList == null || stringList.isEmpty()) { return; } /// 锁住list lock.lock(); try { /// 添加礼物进list giftArray.addAll(stringList); /// 如果没有在加载则开始加载 if (!isLoadEffect) { /// 更改加载状态标记 isLoadEffect = true; loadStartSVGAPlayer(); } } finally { /// 解锁 lock.unlock(); } } }); } /// 礼物特效进来 gift为礼物实体类 public void displayEffectView(final String gift) { queue.execute(new Runnable() { @Override public void run() { /// 如果play_image不存在return if (gift == null || gift.isEmpty()) { return; } /// 将play_image链接转为小写 String playImage = gift; String pathExtension = getFileExtension(playImage).toLowerCase(); /// 判定礼物的后缀是否为svga或者mp4如果非这两种 则return if (!("svga".equals(pathExtension) || "mp4".equals(pathExtension))) { return; } /// 锁住list lock.lock(); try { /// 添加礼物进list giftArray.add(gift); /// 如果没有在加载则开始加载 if (!isLoadEffect) { /// 更改加载状态标记 isLoadEffect = true; loadStartSVGAPlayer(); } } finally { /// 解锁 lock.unlock(); } } }); } public void previewEffectWith(String playImage){ this.isOnece=true; if (playImage.endsWith("mp4")) { downloadAndPlay(getContext(), playImage, new DownloadCallback() { @Override public void onSuccess(File file) { post(() -> { playerMp4View.setVisibility(View.VISIBLE); svgaView.setVisibility(View.GONE); playerMp4View.startPlay(file); }); } @Override public void onFailure(Exception e) { LogUtils.e("MP4下载或播放失败: " + e.getMessage()); // 处理失败情况,继续播放下一个 } }); } else if (playImage.endsWith("svga")) { // File file = downloadAndPlay(getContext(), playImage); post(() -> { playerMp4View.setVisibility(View.GONE); svgaView.setVisibility(View.VISIBLE); svgaView.loadSVGAPlayerWith(playImage, false); }); } } public void openOrCloseEffectViewWith(boolean isShow) { this.isShow = isShow; removeSvgaQueueData(); playerMp4View.stopPlay(); playerMp4View.setVisibility(View.GONE); setVisibility(isShow ? View.VISIBLE : View.GONE); } public void stopPlay() { removeSvgaQueueData(); playerMp4View.stopPlay(); playerMp4View.setVisibility(View.GONE); } private void loadStartSVGAPlayer() { if (!isShow) { /// isshow 为是否开启特效 如果未开启则return return; } String giftModel = null; /// list加锁 lock.lock(); try { /// 如果list长度大于0 if (!giftArray.isEmpty()) { /// gift的实体类则赋值,取list中的第一个数据 giftModel = giftArray.get(0); /// 移除list的第一条数据 giftArray.remove(0); isLoadEffect = true; } else { isLoadEffect = false; } } finally { /// 解锁 lock.unlock(); } if (isLoadEffect && giftModel != null && !TextUtils.isEmpty(giftModel)) { String finalGiftModel = giftModel; post(new Runnable() { @Override public void run() { String playImage = finalGiftModel; if (playImage.endsWith("mp4")) { downloadAndPlay(getContext(), playImage, new DownloadCallback() { @Override public void onSuccess(File file) { post(() -> { playerMp4View.setVisibility(View.VISIBLE); svgaView.setVisibility(View.GONE); playerMp4View.startPlay(file); }); } @Override public void onFailure(Exception e) { LogUtils.e("MP4下载或播放失败: " + e.getMessage()); // 处理失败情况,继续播放下一个 post(() -> { lock.lock(); try { isLoadEffect = false; } finally { lock.unlock(); } loadStartSVGAPlayer(); }); } }); } else if (playImage.endsWith("svga")) { // File file = downloadAndPlay(getContext(), playImage); post(() -> { playerMp4View.setVisibility(View.GONE); svgaView.setVisibility(View.VISIBLE); svgaView.loadSVGAPlayerWith(finalGiftModel, false); }); } else { lock.lock(); try { isLoadEffect = false; } finally { lock.unlock(); } loadStartSVGAPlayer(); // 直接播放缓存文件 } } }); } } public void downloadAndPlay(Context context, String playImage, DownloadCallback callback) { String fileName = playImage.substring(playImage.lastIndexOf("/")); String filePath = context.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(playImage) .build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { LogUtils.e("MP4下载失败: " + e.toString()); // 在主线程中回调失败 post(() -> { if (callback != null) { callback.onFailure(e); } }); } @Override public void onResponse(Call call, Response response) throws IOException { if (response.isSuccessful()) { try (ResponseBody responseBody = response.body()) { if (responseBody != null) { File downloadedFile = new File(filePath); FileOutputStream fos = new FileOutputStream(downloadedFile); fos.write(responseBody.bytes()); fos.close(); // 在主线程中回调成功 post(() -> { if (callback != null) { callback.onSuccess(downloadedFile); } }); } else { // 在主线程中回调失败 post(() -> { if (callback != null) { callback.onFailure(new IOException("Response body is null")); } }); } } catch (Exception e) { LogUtils.e("MP4文件保存失败: " + e.getMessage()); // 在主线程中回调失败 post(() -> { if (callback != null) { callback.onFailure(e); } }); } } else { LogUtils.e("MP4下载响应失败"); // 在主线程中回调失败 post(() -> { if (callback != null) { callback.onFailure(new IOException("Response not successful: " + response.code())); } }); } } }); } else { // 文件已存在,直接回调成功 if (callback != null) { callback.onSuccess(file); } } } // 添加回调接口 public interface DownloadCallback { void onSuccess(File file); void onFailure(Exception e); } public void destroyEffectView() { removeSvgaQueueData(); svgaView.stopEffectSvgaPlay(); playerMp4View.stopPlay(); // 清理监听器 clearPlaybackCompleteListeners(); removeView(playerMp4View); removeView(svgaView); svgaView = null; playerMp4View = null; playModel = null; if (queue != null) { queue.shutdown(); queue = null; } } private void removeSvgaQueueData() { lock.lock(); try { giftArray.clear(); isLoadEffect = false; } finally { lock.unlock(); } } private String getFileExtension(String url) { if (url != null && url.contains(".")) { return url.substring(url.lastIndexOf(".") + 1); } return ""; } @Override public void onStartAnimation(GiftSvgaView view) { } @Override public void onFinishedDisplay(GiftSvgaView view) { post(() -> { if (svgaView!=null) { svgaView.setVisibility(View.GONE); } if (isOnece){ return; } // 通知播放完成 notifyPlaybackComplete(); loadStartSVGAPlayer(); }); } // 在 GiftAnimView 类中添加播放完成监听接口 public interface OnPlaybackCompleteListener { void onPlaybackComplete(); } // 在 GiftAnimView 类中添加成员变量 private List playbackCompleteListeners = new ArrayList<>(); // 在 GiftAnimView 类中添加监听器管理方法 public void addOnPlaybackCompleteListener(OnPlaybackCompleteListener listener) { if (listener != null && !playbackCompleteListeners.contains(listener)) { playbackCompleteListeners.add(listener); } } public void removeOnPlaybackCompleteListener(OnPlaybackCompleteListener listener) { if (listener != null) { playbackCompleteListeners.remove(listener); } } public void clearPlaybackCompleteListeners() { playbackCompleteListeners.clear(); } // 触发播放完成回调的方法 private void notifyPlaybackComplete() { for (OnPlaybackCompleteListener listener : new ArrayList<>(playbackCompleteListeners)) { if (listener != null) { listener.onPlaybackComplete(); } } } }