优化头像框加载、麦圈加载,二卡八放到对应fragment加载。

This commit is contained in:
2026-01-07 16:53:36 +08:00
parent b76136b604
commit d1cd2aeef7
12 changed files with 199 additions and 831 deletions

View File

@@ -31,7 +31,7 @@ public enum QXRoomSeatViewType {
/** /**
* 酒吧 * 酒吧
*/ */
PUB(7,"酒吧"), PUB(11,"酒吧"),
/** /**
* 酒吧 * 酒吧
*/ */

View File

@@ -15,7 +15,7 @@ enum class RoomType(
DATING("交友", 1,3, 4, 8), // 1、3、4、8 均对应交友 DATING("交友", 1,3, 4, 8), // 1、3、4、8 均对应交友
BLACK_ROOM("小黑屋", 6), BLACK_ROOM("小黑屋", 6),
JUKEBOX("点唱", 9), JUKEBOX("点唱", 9),
PUB_ROOM("酒吧", 7), PUB_ROOM("酒吧", 11),
PRIVATE_ROOM("酒吧交友小屋", 12), PRIVATE_ROOM("酒吧交友小屋", 12),
MUTUAL_ENTERTAINMENT("互娱", 7), MUTUAL_ENTERTAINMENT("互娱", 7),
SIGN_CONTRACT("签约", 10); SIGN_CONTRACT("签约", 10);

View File

@@ -107,7 +107,7 @@ public class AgoraManager {
private static List<Music> musicList; private static List<Music> musicList;
private static boolean isBjMusic = false; private static boolean isBjMusic = false;
private static List<SoundLevelUpdateListener> soundLevelUpdateListeners = new CopyOnWriteArrayList<>(); private List<SoundLevelUpdateListener> soundLevelUpdateListeners = new CopyOnWriteArrayList<>();
private static ChannelMediaOptions options; private static ChannelMediaOptions options;
private static RtcConnection connection; private static RtcConnection connection;
private String pkRoomId = ""; private String pkRoomId = "";
@@ -130,8 +130,6 @@ public class AgoraManager {
private final Handler uiHandler = new Handler(Looper.getMainLooper()); private final Handler uiHandler = new Handler(Looper.getMainLooper());
private long lastDispatchTime = 0; private long lastDispatchTime = 0;
// 缓存本次声网回调的音量结果
private final Map<String, Integer> volumeCache = new HashMap<>();
public void setLastRoomId(String value) { public void setLastRoomId(String value) {
lastRoomId = value; lastRoomId = value;
} }
@@ -212,7 +210,7 @@ public class AgoraManager {
try { try {
rtcEngine.setAudioProfile(Constants.AUDIO_PROFILE_MUSIC_HIGH_QUALITY_STEREO, rtcEngine.setAudioProfile(Constants.AUDIO_PROFILE_MUSIC_HIGH_QUALITY_STEREO,
Constants.AUDIO_SCENARIO_GAME_STREAMING); Constants.AUDIO_SCENARIO_GAME_STREAMING);
rtcEngine.enableAudioVolumeIndication(100, 3, false); rtcEngine.enableAudioVolumeIndication(200, 3, true);
rtcEngine.setClientRole(Constants.CLIENT_ROLE_BROADCASTER); rtcEngine.setClientRole(Constants.CLIENT_ROLE_BROADCASTER);
rtcEngine.muteLocalAudioStream(true); // 默认静音 rtcEngine.muteLocalAudioStream(true); // 默认静音
rtcEngine.muteAllRemoteAudioStreams(false); // 监听远端的音频 rtcEngine.muteAllRemoteAudioStreams(false); // 监听远端的音频
@@ -584,6 +582,7 @@ public class AgoraManager {
if (soundLevelUpdateListeners.isEmpty()) return; if (soundLevelUpdateListeners.isEmpty()) return;
for (Map.Entry<String, Integer> entry : volumeSnapshot.entrySet()) { for (Map.Entry<String, Integer> entry : volumeSnapshot.entrySet()) {
for (SoundLevelUpdateListener listener : soundLevelUpdateListeners) { for (SoundLevelUpdateListener listener : soundLevelUpdateListeners) {
if (listener != null) { if (listener != null) {
listener.onRemoteSoundLevelUpdate(entry.getKey(), entry.getValue()); listener.onRemoteSoundLevelUpdate(entry.getKey(), entry.getValue());

View File

@@ -1,13 +1,11 @@
package com.xscm.moduleutil.widget; package com.xscm.moduleutil.widget;
import android.content.Context; import android.content.Context;
import android.opengl.GLSurfaceView;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.Log; import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.SoundEffectConstants;
import android.view.View; import android.view.View;
import android.widget.FrameLayout; import android.widget.FrameLayout;
@@ -16,21 +14,14 @@ import androidx.annotation.Nullable;
import androidx.databinding.DataBindingUtil; import androidx.databinding.DataBindingUtil;
import com.blankj.utilcode.util.LogUtils; 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.SVGACallback;
import com.opensource.svgaplayer.SVGADrawable; import com.opensource.svgaplayer.SVGADrawable;
import com.opensource.svgaplayer.SVGADynamicEntity; import com.opensource.svgaplayer.SVGADynamicEntity;
import com.opensource.svgaplayer.SVGAImageView; import com.opensource.svgaplayer.SVGAImageView;
import com.opensource.svgaplayer.SVGAParser; import com.opensource.svgaplayer.SVGAParser;
import com.opensource.svgaplayer.SVGAVideoEntity; import com.opensource.svgaplayer.SVGAVideoEntity;
import com.tencent.qgame.animplayer.inter.IAnimListener;
import com.xscm.moduleutil.R; import com.xscm.moduleutil.R;
import com.xscm.moduleutil.databinding.RoomViewSvgaAnimBinding; import com.xscm.moduleutil.databinding.RoomViewSvgaAnimBinding;
import com.xscm.moduleutil.utils.SpUtil;
import com.xscm.moduleutil.utils.logger.Logger; import com.xscm.moduleutil.utils.logger.Logger;
import java.io.File; import java.io.File;
@@ -40,11 +31,8 @@ import java.io.InputStream;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.net.URL; import java.net.URL;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map; import java.util.Map;
import java.util.Queue;
import java.util.concurrent.BlockingQueue; import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
@@ -57,9 +45,9 @@ import okhttp3.ResponseBody;
public class AvatarFrameView extends FrameLayout { public class AvatarFrameView extends FrameLayout {
private PlaybackManager playbackManager;
private boolean isMute = false; private boolean isMute = false;
public void setMute(boolean b) { public void setMute(boolean b) {
this.isMute = b; this.isMute = b;
} }
@@ -68,10 +56,7 @@ public class AvatarFrameView extends FrameLayout {
private RenderType renderType; private RenderType renderType;
private SVGAImageView svgaSurface; private SVGAImageView svgaSurface;
private SVGAImageView svgaSurface2;
private final Handler mainHandler = new Handler(Looper.getMainLooper());
private int mType;//1:循环播放 2:播放一次停止播放 private int mType;//1:循环播放 2:播放一次停止播放
private final BlockingQueue<PlayItem> playQueue = new LinkedBlockingQueue<>();
private boolean isPlaying = false; private boolean isPlaying = false;
// 添加销毁标记 // 添加销毁标记
@@ -79,8 +64,6 @@ public class AvatarFrameView extends FrameLayout {
private static final String TAG = "AvatarFrameView"; private static final String TAG = "AvatarFrameView";
private RoomViewSvgaAnimBinding mBinding; private RoomViewSvgaAnimBinding mBinding;
// 内存监控
private static final long MAX_MEMORY_THRESHOLD = 300 * 1024 * 1024; // 300MB
private static final int MAX_SVGA_CACHE_SIZE = 3; private static final int MAX_SVGA_CACHE_SIZE = 3;
private final Map<String, WeakReference<SVGAVideoEntity>> svgaCache = new LruCache<>(MAX_SVGA_CACHE_SIZE); private final Map<String, WeakReference<SVGAVideoEntity>> svgaCache = new LruCache<>(MAX_SVGA_CACHE_SIZE);
@@ -101,25 +84,10 @@ public class AvatarFrameView extends FrameLayout {
} }
private void initViews() { private void initViews() {
// if (isDestroyed) return;
// 初始化 ExoPlayer View
// playerView = new PlayerView(getContext());
// playerView.setUseController(false);
// playerView.setVisibility(View.GONE);
// addView(playerView);
// 初始化 SVGA View // 初始化 SVGA View
svgaSurface = new SVGAImageView(getContext()); svgaSurface = new SVGAImageView(getContext());
svgaSurface.setVisibility(View.GONE); svgaSurface.setVisibility(View.GONE);
addView(svgaSurface); addView(svgaSurface);
svgaSurface2 = new SVGAImageView(getContext());
svgaSurface2.setVisibility(View.GONE);
addView(svgaSurface2);
// 初始化播放管理器
playbackManager = new PlaybackManager(mainHandler);
} }
private String getFileExtension(String url) { private String getFileExtension(String url) {
@@ -130,186 +98,51 @@ public class AvatarFrameView extends FrameLayout {
} }
return ""; return "";
} }
public void setSource(String url, int type2) {
public void playNextFromQueue() { // 添加到播放队列
// if (isDestroyed) return; PlayItem item = new PlayItem(url, type2);
// 确保在主线程中执行 processPlayItem(item);
// if (Looper.myLooper() != Looper.getMainLooper()) { Logger.d("AvatarFrameView", "Added to queue, queue size: url: " + url);
// 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) { private void processPlayItem(PlayItem item) {
try { try {
// clearPrevious();
String ext = getFileExtension(item.url); String ext = getFileExtension(item.url);
if ("svga".equalsIgnoreCase(ext)) { if ("svga".equalsIgnoreCase(ext)) {
mainHandler.post(() -> { renderType = RenderType.SVGA;
renderType = RenderType.SVGA; mType = item.type;
mType = item.type; if (mBinding != null) {
if (mBinding != null && mBinding.playView != null) { mBinding.playView.setVisibility(View.GONE);
mBinding.playView.setVisibility(View.GONE); }
} loadSVGA(item.url);
loadSVGA(item.url);
});
} else if ("mp4".equalsIgnoreCase(ext)) { } else if ("mp4".equalsIgnoreCase(ext)) {
mainHandler.post(() -> { renderType = RenderType.MP4;
renderType = RenderType.MP4; mType = item.type;
mType = item.type; if (mBinding != null) {
if (mBinding != null && mBinding.playView != null) { mBinding.playView.setVisibility(View.VISIBLE);
mBinding.playView.setVisibility(View.VISIBLE); downloadAndPlayMp4(item.url);
} else {
downloadAndPlayMp4(item.url); mBinding = DataBindingUtil.inflate(LayoutInflater.from(getContext()), R.layout.room_view_svga_anim, this, true);
}else { mBinding.playView.setVisibility(View.VISIBLE);
mBinding = DataBindingUtil.inflate(LayoutInflater.from(getContext()), R.layout.room_view_svga_anim, this, true); downloadAndPlayMp4(item.url);
mBinding.playView.setVisibility(View.VISIBLE); }
downloadAndPlayMp4(item.url);
}
});
} else {
// 不支持的格式,直接完成
handlePlaybackComplete();
} }
} catch (Exception e) { } catch (Exception e) {
LogUtils.e(TAG, "Error processing play item: " + e.getMessage()); 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() { public boolean isPlaying() {
if (mBinding != null && mBinding.playView != null) { if (mBinding != null) {
return mBinding.playView.isRunning(); return mBinding.playView.isRunning();
} }
return true; 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; boolean isTxk = false;
public void downloadAndPlayMp4(String url) { public void downloadAndPlayMp4(String url) {
// 提取文件名 // 提取文件名
String fileName = url.substring(url.lastIndexOf("/")); String fileName = url.substring(url.lastIndexOf("/"));
String filePath = getContext().getCacheDir().getAbsolutePath() + fileName; String filePath = getContext().getCacheDir().getAbsolutePath() + fileName;
@@ -330,12 +163,6 @@ public class AvatarFrameView extends FrameLayout {
@Override @Override
public void onFailure(Call call, IOException e) { public void onFailure(Call call, IOException e) {
LogUtils.e("MP4下载失败: " + e.toString()); LogUtils.e("MP4下载失败: " + e.toString());
mainHandler.post(() -> {
// 检查是否已销毁
if (!isDestroyed) {
onPlaybackComplete();
}
});
} }
// 更简单的优化版本 // 更简单的优化版本
@@ -371,63 +198,36 @@ public class AvatarFrameView extends FrameLayout {
fos.flush(); fos.flush();
isTxk = true; isTxk = true;
mainHandler.post(() -> { // 关键在执行UI操作前再次检查是否已销毁
// 关键在执行UI操作前再次检查是否已销毁 if (downloadedFile.exists()) {
if (downloadedFile.exists()) { LogUtils.d("@@@@Thread", Thread.currentThread().getName());
LogUtils.d("@@@@Thread", Thread.currentThread().getName()); playMp4File(downloadedFile); // 使用正确的文件引用
playMp4File(downloadedFile); // 使用正确的文件引用 } else {
} else { LogUtils.w(TAG, "View destroyed or file not exist after download");
LogUtils.w(TAG, "View destroyed or file not exist after download"); }
onPlaybackComplete();
}
});
} catch (IOException e) { } catch (IOException e) {
LogUtils.e("MP4文件保存失败: " + e.getMessage()); LogUtils.e("MP4文件保存失败: " + e.getMessage());
mainHandler.post(() -> {
if (!isDestroyed) {
onPlaybackComplete();
}
});
} }
} else {
mainHandler.post(() -> {
if (!isDestroyed) {
onPlaybackComplete();
}
});
} }
} catch (Exception e) { } catch (Exception e) {
LogUtils.e("MP4文件保存失败: " + e.getMessage()); LogUtils.e("MP4文件保存失败: " + e.getMessage());
mainHandler.post(() -> {
if (!isDestroyed) {
onPlaybackComplete();
}
});
} }
} else { } else {
LogUtils.e("MP4下载响应失败"); LogUtils.e("MP4下载响应失败");
mainHandler.post(() -> {
if (!isDestroyed) {
onPlaybackComplete();
}
});
} }
} }
}); });
} else { } else {
isTxk = true; isTxk = true;
LogUtils.e("有缓存"); // 检查是否已销毁
mainHandler.post(() -> { if (file.exists()) {
// 检查是否已销毁 LogUtils.e("有缓存:" + file.exists() + "====" + file.getAbsolutePath());
if (file.exists()) { playMp4File(file);
LogUtils.e("有缓存:"+file.exists()+"===="+file.getAbsolutePath()); } else {
playMp4File(file); LogUtils.w(TAG, "有缓存2222222222222");
} else { }
LogUtils.w(TAG, "有缓存2222222222222");
}
});
} }
} }
@@ -436,13 +236,11 @@ public class AvatarFrameView extends FrameLayout {
// 双重检查确保组件未被销毁 // 双重检查确保组件未被销毁
if (isDestroyed) { if (isDestroyed) {
LogUtils.w(TAG, "Attempt to play MP4 file after view destroyed"); LogUtils.w(TAG, "Attempt to play MP4 file after view destroyed");
onPlaybackComplete();
return; return;
} }
if (mBinding == null || mBinding.playView == null) { if (mBinding == null) {
LogUtils.w(TAG, "PlayView is null"); LogUtils.w(TAG, "PlayView is null");
onPlaybackComplete();
return; return;
} }
@@ -453,27 +251,23 @@ public class AvatarFrameView extends FrameLayout {
} else { } else {
mBinding.playView.setLoop(1); // 播放一次 mBinding.playView.setLoop(1); // 播放一次
} }
mBinding.playView.setMute(isMute); mBinding.playView.setMute(isMute);
// 开始播放前检查视图状态 // 开始播放前检查视图状态
if (!isDestroyed && mBinding != null && mBinding.playView != null) { if (!isDestroyed && mBinding != null && mBinding.playView != null) {
mBinding.playView.startPlay(file); mBinding.playView.startPlay(file);
} else { } else {
LogUtils.w(TAG, "View was destroyed before MP4 playback started"); LogUtils.w(TAG, "View was destroyed before MP4 playback started");
onPlaybackComplete();
} }
} else { } else {
LogUtils.e("播放MP4文件出错: 文件不存在或已损坏"); LogUtils.e("播放MP4文件出错: 文件不存在或已损坏");
onPlaybackComplete();
} }
} catch (Exception e) { } catch (Exception e) {
LogUtils.e("播放MP4文件出错: " + e.getMessage()); LogUtils.e("播放MP4文件出错: " + e.getMessage());
onPlaybackComplete();
} }
} }
private void handleSVGAComplete(SVGAVideoEntity videoItem, String url) { private void handleSVGAComplete(SVGAVideoEntity videoItem, String url) {
if (svgaSurface == null) { if (svgaSurface == null) {
onPlaybackComplete();
return; return;
} }
@@ -496,7 +290,6 @@ public class AvatarFrameView extends FrameLayout {
svgaSurface.stopAnimation(); svgaSurface.stopAnimation();
svgaSurface.clearAnimation(); svgaSurface.clearAnimation();
svgaSurface.setImageDrawable(null); svgaSurface.setImageDrawable(null);
onPlaybackComplete();
} }
} }
@@ -506,11 +299,8 @@ public class AvatarFrameView extends FrameLayout {
@Override @Override
public void onFinished() { public void onFinished() {
// if (isDestroyed) return;
if (mType == 1) { // 循环播放 if (mType == 1) { // 循环播放
// 继续循环播放 // 继续循环播放
} else {
onPlaybackComplete();
} }
} }
}); });
@@ -523,10 +313,6 @@ public class AvatarFrameView extends FrameLayout {
svgaSurface.startAnimation(); svgaSurface.startAnimation();
} catch (Exception e) { } catch (Exception e) {
LogUtils.e(TAG, "Error handling SVGA completion: " + e.getMessage()); LogUtils.e(TAG, "Error handling SVGA completion: " + e.getMessage());
// isPlaying = false;
// playNextFromQueue();
handlePlaybackComplete();
} }
} }
@@ -536,13 +322,8 @@ public class AvatarFrameView extends FrameLayout {
svgaSurface.clearAnimation(); svgaSurface.clearAnimation();
svgaSurface.setImageDrawable(null); svgaSurface.setImageDrawable(null);
} }
if (svgaSurface2 != null) {
svgaSurface2.stopAnimation();
svgaSurface2.clearAnimation();
svgaSurface.setImageDrawable(null);
}
// 增加空值检查 // 增加空值检查
if (mBinding != null && mBinding.playView != null) { if (mBinding != null) {
mBinding.playView.stopPlay(); mBinding.playView.stopPlay();
} }
} }
@@ -566,16 +347,7 @@ public class AvatarFrameView extends FrameLayout {
@Override @Override
public void onFinished() { public void onFinished() {
if (Looper.myLooper() != Looper.getMainLooper()) { isPlaying = false;
mainHandler.post(() -> {
isPlaying = false;
// 添加延迟确保状态更新
mainHandler.postDelayed(AvatarFrameView.this::playNextFromQueue, 50);
});
} else {
isPlaying = false;
mainHandler.postDelayed(AvatarFrameView.this::playNextFromQueue, 50);
}
} }
}); });
// 设置循环次数 // 设置循环次数
@@ -588,21 +360,16 @@ public class AvatarFrameView extends FrameLayout {
} catch (Exception e) { } catch (Exception e) {
LogUtils.e(TAG, "Error playing cached SVGA: " + e.getMessage()); LogUtils.e(TAG, "Error playing cached SVGA: " + e.getMessage());
isPlaying = false; isPlaying = false;
mainHandler.postDelayed(AvatarFrameView.this::playNextFromQueue, 50);
// playNextFromQueue();
} }
} }
private void loadNewSVGA(String url) { private void loadNewSVGA(String url) {
try { try {
new SVGAParser(getContext()).parse(new URL(url), new SVGAParser.ParseCompletion() { new SVGAParser(getContext()).parse(new URL(url), new SVGAParser.ParseCompletion() {
@Override @Override
public void onComplete(SVGAVideoEntity videoItem) { public void onComplete(SVGAVideoEntity videoItem) {
// if (isDestroyed) return;
if (Looper.myLooper() != Looper.getMainLooper()) { if (Looper.myLooper() != Looper.getMainLooper()) {
mainHandler.post(() -> handleSVGAComplete(videoItem, url)); handleSVGAComplete(videoItem, url);
} else { } else {
handleSVGAComplete(videoItem, url); handleSVGAComplete(videoItem, url);
} }
@@ -610,32 +377,16 @@ public class AvatarFrameView extends FrameLayout {
@Override @Override
public void onError() { public void onError() {
// if (isDestroyed) return; isPlaying = false;
if (Looper.myLooper() != Looper.getMainLooper()) {
mainHandler.post(() -> {
isPlaying = false;
playNextFromQueue();
});
} else {
isPlaying = false;
playNextFromQueue();
}
} }
}); });
} catch (Exception e) { } catch (Exception e) {
LogUtils.e(TAG, "Error parsing SVGA: " + e.getMessage()); LogUtils.e(TAG, "Error parsing SVGA: " + e.getMessage());
isPlaying = false; isPlaying = false;
playNextFromQueue();
} }
} }
private void loadSVGA(String url) { private void loadSVGA(String url) {
if (Looper.myLooper() != Looper.getMainLooper()) {
mainHandler.post(() -> loadSVGA(url));
return;
}
try { try {
svgaSurface.setVisibility(View.VISIBLE); svgaSurface.setVisibility(View.VISIBLE);
@@ -653,7 +404,6 @@ public class AvatarFrameView extends FrameLayout {
} catch (Exception e) { } catch (Exception e) {
LogUtils.e(TAG, "Error loading SVGA: " + e.getMessage()); LogUtils.e(TAG, "Error loading SVGA: " + e.getMessage());
isPlaying = false; isPlaying = false;
playNextFromQueue();
} }
svgaSurface.setVisibility(View.VISIBLE); svgaSurface.setVisibility(View.VISIBLE);
@@ -683,7 +433,6 @@ public class AvatarFrameView extends FrameLayout {
@Override @Override
public void onFinished() { public void onFinished() {
isPlaying = false; isPlaying = false;
playNextFromQueue();
} }
}); });
@@ -693,7 +442,6 @@ public class AvatarFrameView extends FrameLayout {
@Override @Override
public void onError() { public void onError() {
isPlaying = false; isPlaying = false;
playNextFromQueue();
} }
}); });
} catch (Exception e) { } catch (Exception e) {
@@ -716,7 +464,6 @@ public class AvatarFrameView extends FrameLayout {
} }
// 隐藏所有视图 // 隐藏所有视图
// if (playerView != null) playerView.setVisibility(View.GONE);
if (svgaSurface != null) svgaSurface.setVisibility(View.GONE); if (svgaSurface != null) svgaSurface.setVisibility(View.GONE);
@@ -750,39 +497,7 @@ public class AvatarFrameView extends FrameLayout {
*/ */
private void releaseResources() { private void releaseResources() {
LogUtils.d(TAG, "Releasing all resources"); LogUtils.d(TAG, "Releasing all resources");
performUICleanup();
// 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());
}
} }
/** /**
@@ -791,31 +506,16 @@ public class AvatarFrameView extends FrameLayout {
private void performUICleanup() { private void performUICleanup() {
try { try {
// 停止并清理播放器 // 停止并清理播放器
if (mBinding != null && mBinding.playView != null) { if (mBinding != null) {
try { try {
mBinding.playView.stopPlay(); mBinding.playView.stopPlay();
} catch (Exception e) { } catch (Exception e) {
Logger.e(TAG, "Error stopping playView: " + e.getMessage()); 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 资源 // 清理 SVGA 资源
if (svgaSurface != null) { if (svgaSurface != null) {
try { try {
// svgaSurface.pauseAnimation();
// svgaSurface.clearAnimation();
// svgaSurface.setImageDrawable(null);
svgaSurface.stopAnimation(true); svgaSurface.stopAnimation(true);
svgaSurface.clear(); svgaSurface.clear();
svgaSurface.clearAnimation(); svgaSurface.clearAnimation();
@@ -834,86 +534,23 @@ public class AvatarFrameView extends FrameLayout {
*/ */
public void release() { public void release() {
Logger.d("AvatarFrameView", "Public release called"); Logger.d("AvatarFrameView", "Public release called");
// if (isDestroyed) return;
// 确保在主线程中执行
// if (Looper.myLooper() != Looper.getMainLooper()) {
// mainHandler.post(this::release);
// return;
// }
isDestroyed = true; isDestroyed = true;
try { try {
// 清空播放队列 // 清空播放队列
clearQueue(); clearQueue();
// 清理播放管理器
if (playbackManager != null) {
playbackManager.reset();
}
// 释放所有资源 // 释放所有资源
releaseResources(); releaseResources();
// 延迟清理其他资源
mainHandler.postDelayed(() -> {
// 清理 binding
if (mBinding != null) {
mBinding = null;
}
}, 100);
// 清理 binding
if (mBinding != null) {
mBinding = null;
}
} catch (Exception e) { } catch (Exception e) {
LogUtils.e(TAG, "Error in AvatarFrameView release: " + e.getMessage()); LogUtils.e(TAG, "Error in AvatarFrameView release: " + e.getMessage());
} finally {
// 建议进行垃圾回收
// MemoryOptimizationUtils.forceGC();
} }
} }
public void clearQueue() { public void clearQueue() {
// if (isDestroyed) return;
playQueue.clear();
isPlaying = false; isPlaying = false;
// 清理播放管理器中的任务
if (playbackManager != null) {
playbackManager.reset();
}
// 清理当前正在播放的内容 // 清理当前正在播放的内容
clearPrevious(); clearPrevious();
} }
// 在类成员变量中添加
private static final int PLAYBACK_TIMEOUT = 10000; // 10秒超时
private Map<String, Long> 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 { private static class PlayItem {
String url; String url;
int type; int type;
@@ -923,167 +560,4 @@ public class AvatarFrameView extends FrameLayout {
this.type = type; 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<Map.Entry<String, WeakReference<SVGAVideoEntity>>> iterator =
svgaCache.entrySet().iterator();
if (iterator.hasNext()) {
iterator.next(); // 跳过最新的
if (iterator.hasNext()) {
iterator.remove(); // 移除较旧的
}
}
}
// 建议进行垃圾回收
System.gc();
}
}
} }

View File

@@ -37,6 +37,7 @@ import com.xscm.moduleutil.event.RoomFaceEvent;
import com.xscm.moduleutil.interfaces.IBaseWheat; import com.xscm.moduleutil.interfaces.IBaseWheat;
import com.xscm.moduleutil.interfaces.SoundLevelUpdateListener; import com.xscm.moduleutil.interfaces.SoundLevelUpdateListener;
import com.xscm.moduleutil.rtc.AgoraManager; import com.xscm.moduleutil.rtc.AgoraManager;
import com.xscm.moduleutil.utils.ImageUtils;
import com.xscm.moduleutil.utils.SpUtil; import com.xscm.moduleutil.utils.SpUtil;
import com.xscm.moduleutil.utils.logger.Logger; import com.xscm.moduleutil.utils.logger.Logger;
@@ -63,6 +64,7 @@ public abstract class BaseWheatView extends ConstraintLayout implements IBaseWhe
public TextView tv_time_pk; public TextView tv_time_pk;
public RoomPitBean pitBean;//麦位数据 public RoomPitBean pitBean;//麦位数据
public String roomId;//房间id public String roomId;//房间id
CountDownTimer mCountDownTimer; CountDownTimer mCountDownTimer;
@@ -82,17 +84,14 @@ public abstract class BaseWheatView extends ConstraintLayout implements IBaseWhe
public ImageView iv_on_line; public ImageView iv_on_line;
private boolean showGiftAnim = true;//显示麦位动画 private boolean showGiftAnim = true;//显示麦位动画
private ImageView iv_tag_type; private ImageView iv_tag_type;
// 当前音量监听器,用于防止重复添加
private SoundLevelUpdateListener currentSoundLevelListener;
private TextView tv_zhul; private TextView tv_zhul;
private SVGAParser mParser; private SVGAParser mParser;
private final SVGAParser parser = new SVGAParser(CommonAppContext.getInstance()); private String micCycle = "";
public boolean isMentorShip = false; public boolean isMentorShip = false;
private SoundLevelUpdateListener soundLevelUpdateListener;
public BaseWheatView(Context context) { public BaseWheatView(Context context) {
this(context, null, 0); this(context, null, 0);
@@ -112,6 +111,7 @@ public abstract class BaseWheatView extends ConstraintLayout implements IBaseWhe
mIvSex = findViewById(R.id.iv_sex); mIvSex = findViewById(R.id.iv_sex);
mIvFrame = findViewById(R.id.iv_frame); mIvFrame = findViewById(R.id.iv_frame);
mIvRipple = findViewById(R.id.iv_ripple); mIvRipple = findViewById(R.id.iv_ripple);
mIvFace = findViewById(R.id.iv_face); mIvFace = findViewById(R.id.iv_face);
mIvShutup = findViewById(R.id.iv_shutup); mIvShutup = findViewById(R.id.iv_shutup);
tvTime = findViewById(R.id.tv_time); tvTime = findViewById(R.id.tv_time);
@@ -179,33 +179,61 @@ public abstract class BaseWheatView extends ConstraintLayout implements IBaseWhe
setCardiac(pitBean.getCharm(), getTzbl()); setCardiac(pitBean.getCharm(), getTzbl());
if (bean.getUser_id() != null && !bean.getUser_id().equals("0") && !bean.getUser_id().isEmpty()) { if (bean.getUser_id() != null && !bean.getUser_id().equals("0") && !bean.getUser_id().isEmpty()) {
if (bean.getIs_online()==1){ if (bean.getIs_online() == 1) {
iv_on_line.setVisibility(GONE); iv_on_line.setVisibility(GONE);
}else if (bean.getIs_online()==2){ } else if (bean.getIs_online() == 2) {
if (!bean.getUser_id().equals(SpUtil.getUserId()+"")) { if (!bean.getUser_id().equals(SpUtil.getUserId() + "")) {
iv_on_line.setVisibility(VISIBLE); iv_on_line.setVisibility(VISIBLE);
} }
}else { } else {
iv_on_line.setVisibility(GONE); iv_on_line.setVisibility(GONE);
} }
} else { } else {
iv_on_line.setVisibility(GONE); iv_on_line.setVisibility(GONE);
} }
if (mParser == null || (!TextUtils.isEmpty(pitBean.getMic_cycle()) && !micCycle.equals(pitBean.getMic_cycle()))) {
LogUtils.e("这是一个很诡异的东西 " + (mParser == null) +",pitBean.getMic_cycle():"+pitBean.getMic_cycle());
if (mParser != null) {
mParser = null;
}
micCycle = pitBean.getMic_cycle();
mParser = new SVGAParser(getContext());
if (TextUtils.isEmpty(pitBean.getMic_cycle())) {
mParser.decodeFromAssets("mic.svga", new SVGAParser.ParseCompletion() {
@Override
public void onComplete(@Nullable SVGAVideoEntity videoItem) {
if (videoItem != null) {
mIvRipple.setVideoItem(videoItem);
}
}
parser.decodeFromAssets("mic.svga", new SVGAParser.ParseCompletion() { @Override
@Override public void onError() {
public void onComplete(@Nullable SVGAVideoEntity videoItem) { Log.e("SVGA", "解析 ripple.svga 失败");
if (videoItem != null) { }
mIvRipple.setVideoItem(videoItem); });
} else {
try {
mParser.decodeFromURL(new URL(pitBean.getMic_cycle()),
new SVGAParser.ParseCompletion() {
@Override
public void onComplete(@NotNull SVGAVideoEntity svgaVideoEntity) {
mIvRipple.setImageDrawable(new SVGADrawable(svgaVideoEntity));
mIvRipple.startAnimation();
}
@Override
public void onError() {
LogUtils.e("BaseWheatView", "解析 mic_cycle 失败");
}
});
} catch (MalformedURLException ignored) {
LogUtils.e("BaseWheatView", "解析 mic_cycle 失败");
} }
} }
}
@Override
public void onError() {
Log.e("SVGA", "解析 ripple.svga 失败");
}
});
setPitData(bean); setPitData(bean);
@@ -214,7 +242,7 @@ public abstract class BaseWheatView extends ConstraintLayout implements IBaseWhe
mIvRipple.setScaleX(1.1f); mIvRipple.setScaleX(1.1f);
mIvRipple.setScaleY(1.1f); mIvRipple.setScaleY(1.1f);
} }
if (!isMentorShip){ if (!isMentorShip) {
//心动值 //心动值
//显示心动 //显示心动
@@ -259,13 +287,18 @@ public abstract class BaseWheatView extends ConstraintLayout implements IBaseWhe
} }
} }
AgoraManager.getInstance().addSoundLevelListener(new SoundLevelUpdateListener() { if (soundLevelUpdateListener != null){
AgoraManager.getInstance().removeSoundLevelListener(soundLevelUpdateListener);
}
soundLevelUpdateListener = new SoundLevelUpdateListener() {
@Override @Override
public void onRemoteSoundLevelUpdate(String userId, int soundLevel) { public void onRemoteSoundLevelUpdate(String userId, int soundLevel) {
if (mIvRipple == null) return; if (mIvRipple == null || pitBean.getUser_id().equals("0")) return;
if (!userId.equals(pitBean.getUser_id())) return; if (!userId.equals(pitBean.getUser_id())) return;
boolean nowSpeaking = soundLevel > 0; boolean nowSpeaking = soundLevel > 0;
updateSpeakingState(nowSpeaking); updateSpeakingState(nowSpeaking);
} }
@@ -290,9 +323,13 @@ public abstract class BaseWheatView extends ConstraintLayout implements IBaseWhe
if (mIvRipple == null) if (mIvRipple == null)
return; return;
mIvRipple.setVisibility(INVISIBLE); mIvRipple.setVisibility(INVISIBLE);
Log.e("SVGA", "-------"+pitBean.getUser_id());
} }
} }
}); };
AgoraManager.getInstance().addSoundLevelListener(soundLevelUpdateListener);
} }
@@ -344,9 +381,11 @@ public abstract class BaseWheatView extends ConstraintLayout implements IBaseWhe
} }
@Override @Override
public void onError() {} public void onError() {
}
}); });
} catch (MalformedURLException ignored) {} } catch (MalformedURLException ignored) {
}
} }
public void setCharm(String charm) { public void setCharm(String charm) {
@@ -398,13 +437,13 @@ public abstract class BaseWheatView extends ConstraintLayout implements IBaseWhe
public void setOnlineStatus() { public void setOnlineStatus() {
if (pitBean.getUser_id() != null && !pitBean.getUser_id().equals("0") && !pitBean.getUser_id().isEmpty()) { if (pitBean.getUser_id() != null && !pitBean.getUser_id().equals("0") && !pitBean.getUser_id().isEmpty()) {
if (pitBean.getIs_online()==1){ if (pitBean.getIs_online() == 1) {
iv_on_line.setVisibility(GONE); iv_on_line.setVisibility(GONE);
}else if (pitBean.getIs_online()==2){ } else if (pitBean.getIs_online() == 2) {
if (!pitBean.getUser_id().equals(SpUtil.getUserId()+"")) { if (!pitBean.getUser_id().equals(SpUtil.getUserId() + "")) {
iv_on_line.setVisibility(VISIBLE); iv_on_line.setVisibility(VISIBLE);
} }
}else { } else {
iv_on_line.setVisibility(GONE); iv_on_line.setVisibility(GONE);
} }
} else { } else {
@@ -423,6 +462,7 @@ public abstract class BaseWheatView extends ConstraintLayout implements IBaseWhe
showGiftAnim = false; showGiftAnim = false;
releaseCountDownTimer(); releaseCountDownTimer();
super.onDetachedFromWindow(); super.onDetachedFromWindow();
mParser = null;
} }
/** /**
@@ -742,7 +782,6 @@ public abstract class BaseWheatView extends ConstraintLayout implements IBaseWhe
mIvFace.addData(new FaceBean(roomRollModel.getNumber(), 2)); mIvFace.addData(new FaceBean(roomRollModel.getNumber(), 2));
} }
/** /**
* 是否主持 * 是否主持
* *

View File

@@ -74,7 +74,7 @@ public class RoomKtvWheatView extends BaseWheatView {
sex = bean.getSex(); sex = bean.getSex();
if (isOn()) { if (isOn()) {
//开启声浪 //开启声浪
if (mCharmView != null) { if (mIvRipple != null) {
mIvRipple.stopAnimation(true); mIvRipple.stopAnimation(true);
mIvRipple.setVisibility(VISIBLE); mIvRipple.setVisibility(VISIBLE);
} }
@@ -103,12 +103,7 @@ public class RoomKtvWheatView extends BaseWheatView {
mIvTagBoss.setVisibility(VISIBLE); mIvTagBoss.setVisibility(VISIBLE);
ImageUtils.loadRes(isLocked() ? R.mipmap.room_ic_wheat_default_suo : R.mipmap.room_ic_wheat_default, mRiv); ImageUtils.loadRes(isLocked() ? R.mipmap.room_ic_wheat_default_suo : R.mipmap.room_ic_wheat_default, mRiv);
} else { } else {
// mIvTagBoss.setVisibility(GONE);
// @DrawableRes int origin = getOriginImage();
// ImageUtils.loadRes(isLocked() ? R.mipmap.room_ic_wheat_default_suo :
// (origin == 0 ? R.mipmap.room_ic_wheat_default : origin), mRiv);
mRiv.setImageResource(bean.getIs_lock() == 1 ? R.mipmap.room_ic_wheat_default_suo : R.mipmap.room_ic_wheat_default); mRiv.setImageResource(bean.getIs_lock() == 1 ? R.mipmap.room_ic_wheat_default_suo : R.mipmap.room_ic_wheat_default);
// ImageUtils.loadRes(isLocked() ? R.mipmap.room_ic_wheat_default_suo : R.mipmap.room_ic_wheat_default, mRiv);
} }
if (isMute()) { if (isMute()) {
ImageUtils.loadRes(R.mipmap.room_microphone_off, mIvSex); ImageUtils.loadRes(R.mipmap.room_microphone_off, mIvSex);

View File

@@ -1,169 +0,0 @@
package com.xscm.moduleutil.widget;
import android.content.Context;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.opensource.svgaplayer.SVGAImageView;
import com.xscm.moduleutil.R;
import com.xscm.moduleutil.bean.room.RoomPitBean;
import com.xscm.moduleutil.utils.ImageUtils;
public class RoomSingWheatView extends LinearLayout {
public ImageView mRiv;
public ImageView mIvGift;
public WheatCharmView mCharmView;
public TextView mTvName;
public ImageView mIvSex;
public AvatarFrameView mIvFrame;
public AvatarFrameView mIvRipple;
public ExpressionImgView mIvFace;
public ImageView mIvShutup;
public TextView tvTime;
public TextView mTvNo;
public TextView tv_time_pk;
public RoomPitBean pitBean;//麦位数据
public String roomId;//房间id
public static final String WHEAT_BOSS = "8";//老板位
public static final String WHEAT_HOST = "9";//主持位
public float oX;
public float oY;
boolean closePhone = false;//自己麦位关闭话筒,用于判断声纹显示
public String pitNumber;
public int pitImageVId;
// public ImageView iv_on_line;
private boolean showGiftAnim = true;//显示麦位动画
private ImageView iv_tag_type;
private TextView tv_zhul;
public RoomSingWheatView(@NonNull Context context) {
this(context, null);
}
public RoomSingWheatView(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public RoomSingWheatView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context);
}
private void initView(Context context) {
// 确保布局被正确加载
inflate(context, getLayoutId(), this);
// 初始化所有视图组件
mRiv = findViewById(R.id.riv);
mIvGift = findViewById(R.id.iv_gift);
mCharmView = findViewById(R.id.charm_view);
mTvName = findViewById(R.id.tv_name);
mIvSex = findViewById(R.id.iv_sex);
mIvFrame = findViewById(R.id.iv_frame);
mIvRipple = findViewById(R.id.iv_ripple);
mIvFace = findViewById(R.id.iv_face);
mIvShutup = findViewById(R.id.iv_shutup);
tvTime = findViewById(R.id.tv_time);
tv_time_pk = findViewById(R.id.tv_time_pk);
mTvNo = findViewById(R.id.tv_no);
// iv_on_line = findViewById(R.id.iv_online);
iv_tag_type = findViewById(R.id.iv_tag_type);
tv_zhul = findViewById(R.id.tv_zhul);
// 设置初始位置
if (mIvGift != null) {
oX = mIvGift.getX();
oY = mIvGift.getY();
}
}
protected int getLayoutId() {
return R.layout.room_view_sing_wheat;
}
public void setData(RoomPitBean bean) {
this.pitBean = bean;
if (bean == null) return;
// 添加空值检查防止NPE
if (mTvName == null) {
// 可能布局未正确加载,尝试重新初始化
initView(getContext());
if (mTvName == null) {
// 如果仍然为null记录日志并返回
android.util.Log.e("RoomSingWheatView", "mTvName is still null after re-initialization");
return;
}
}
if (isOn()) {
//开启声浪
mIvRipple.startLoopingSvga("mic.svga");
mIvRipple.setVisibility(VISIBLE);
mTvName.setText(bean.getNickname());
ImageUtils.loadHeadCC(bean.getAvatar(), mRiv);
if (TextUtils.isEmpty(pitBean.getDress())) {
if (mIvFrame != null) mIvFrame.setVisibility(INVISIBLE);
} else {
if (mIvFrame != null) {
mIvFrame.setVisibility(VISIBLE);
mIvFrame.setSource(pitBean.getDress(), 3);
}
}
} else {
String pitText = "-1".equals(pitNumber) ? "" :
"9".equals(pitNumber) ? "主持位" :
"10".equals(pitNumber) ? "嘉宾位" :
pitNumber + "号麦位";
mTvName.setText(pitText);
if (mIvFrame != null) mIvFrame.setVisibility(INVISIBLE);
if (mIvFace != null) mIvFace.remove();
//停止声浪
mIvRipple.stopSvga();
mIvRipple.setVisibility(GONE);
}
// 更新魅力值视图
if (mCharmView != null) {
if (pitBean.getNickname() == null || pitBean.getNickname().isEmpty()) {
mCharmView.setVisibility(GONE);
} else {
mCharmView.setVisibility(VISIBLE);
}
}
// 更新PK状态
if (tv_time_pk != null) {
if (pitBean.is_pk() && pitBean.getUser_id() != null &&
!pitBean.getUser_id().equals("0") && !pitBean.getUser_id().isEmpty()) {
tv_time_pk.setVisibility(VISIBLE);
if (mCharmView != null) mCharmView.setVisibility(GONE);
} else {
tv_time_pk.setVisibility(GONE);
if (mCharmView != null) mCharmView.setVisibility(VISIBLE);
}
}
}
private boolean isOn() {
return pitBean != null && !TextUtils.isEmpty(pitBean.getUser_id()) && !"0".equals(pitBean.getUser_id());
}
}

View File

@@ -10,18 +10,6 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<!-- <com.opensource.svgaplayer.SVGAImageView-->
<!-- android:id="@+id/image"-->
<!-- android:layout_width="0dp"-->
<!-- android:layout_height="0dp"-->
<!-- android:scaleType="fitCenter"-->
<!-- app:autoPlay="true"-->
<!-- app:layout_constraintBottom_toBottomOf="parent"-->
<!-- app:layout_constraintEnd_toEndOf="parent"-->
<!-- app:layout_constraintStart_toStartOf="parent"-->
<!-- app:layout_constraintTop_toTopOf="parent"-->
<!-- app:loopCount="1" />-->
<com.tencent.qgame.animplayer.AnimView <com.tencent.qgame.animplayer.AnimView
android:id="@+id/play_view" android:id="@+id/play_view"
android:layout_width="0dp" android:layout_width="0dp"
@@ -29,8 +17,6 @@
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent" />
/>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</layout> </layout>

View File

@@ -96,9 +96,7 @@ open class Application : CommonAppContext() {
configureLeakCanary() configureLeakCanary()
// 初始化并预绘制视图 二卡八列
WheatLayoutSingManager.init(this)
WheatLayoutSingManager.getInstance().setWheatData(null)
// 默认情况下SVGA 内部不会输出任何 log所以需要手动设置为 true // 默认情况下SVGA 内部不会输出任何 log所以需要手动设置为 true
SVGALogger.setLogEnabled(false) SVGALogger.setLogEnabled(false)

View File

@@ -484,26 +484,30 @@ public class RoomAuctionFragment extends BaseMvpFragment<RoomAuctionPresenterTow
private void getTextView() { private void getTextView() {
int defaultColor = ContextCompat.getColor(requireContext(), com.xscm.moduleutil.R.color.color_0DFFB9); // 亲密拍默认颜色(绿色) try {
int selectedColor = ContextCompat.getColor(requireContext(), com.xscm.moduleutil.R.color.color_white); // 选中颜色(色) int defaultColor = ContextCompat.getColor(requireContext(), com.xscm.moduleutil.R.color.color_0DFFB9); // 亲密拍默认颜色(绿色)
int clickedColor = ContextCompat.getColor(requireContext(), com.xscm.moduleutil.R.color.color_BB8BE2); // 真爱拍选中颜色(色) int selectedColor = ContextCompat.getColor(requireContext(), com.xscm.moduleutil.R.color.color_white); // 选中颜色(色)
float defaultSize = 16f; // 默认字体大小 int clickedColor = ContextCompat.getColor(requireContext(), com.xscm.moduleutil.R.color.color_BB8BE2); // 真爱拍选中颜色(蓝色)
float selectedSize = 24f; // 选中字体大小 float defaultSize = 16f; // 默认字体大小
mBinding.zhenai.setText("真爱拍"); float selectedSize = 24f; // 选中字体大小
mBinding.qinmi.setText("亲密"); mBinding.zhenai.setText("真爱");
// 根据type设置初始状态 mBinding.qinmi.setText("亲密拍");
if (type == 1) { // 根据type设置初始状态
// type=1 真爱拍模式 if (type == 1) {
mBinding.zhenai.setTextColor(clickedColor); // 真爱拍蓝色 // type=1 真爱拍模式
mBinding.zhenai.setTextSize(TypedValue.COMPLEX_UNIT_SP, selectedSize); // 真爱拍24号字体 mBinding.zhenai.setTextColor(clickedColor); // 真爱拍蓝色
mBinding.qinmi.setTextColor(selectedColor); // 亲密拍白色 mBinding.zhenai.setTextSize(TypedValue.COMPLEX_UNIT_SP, selectedSize); // 真爱拍24号字体
mBinding.qinmi.setTextSize(TypedValue.COMPLEX_UNIT_SP, defaultSize); // 亲密拍16号字体 mBinding.qinmi.setTextColor(selectedColor); // 亲密拍白色
} else { mBinding.qinmi.setTextSize(TypedValue.COMPLEX_UNIT_SP, defaultSize); // 亲密拍16号字体
// type=2 亲密拍模式 } else {
mBinding.qinmi.setTextColor(defaultColor); // 亲密拍绿色 // type=2 亲密拍模式
mBinding.qinmi.setTextSize(TypedValue.COMPLEX_UNIT_SP, selectedSize); // 亲密拍24号字体 mBinding.qinmi.setTextColor(defaultColor); // 亲密拍绿色
mBinding.zhenai.setTextColor(selectedColor); // 真爱拍白色 mBinding.qinmi.setTextSize(TypedValue.COMPLEX_UNIT_SP, selectedSize); // 亲密拍24号字体
mBinding.zhenai.setTextSize(TypedValue.COMPLEX_UNIT_SP, defaultSize); // 真爱拍16号字体 mBinding.zhenai.setTextColor(selectedColor); // 真爱拍白色
mBinding.zhenai.setTextSize(TypedValue.COMPLEX_UNIT_SP, defaultSize); // 真爱拍16号字体
}
}catch (Exception e){
LogUtils.e("getTextView",e.getMessage());
} }
mBinding.zhenai.setOnClickListener(v -> { mBinding.zhenai.setOnClickListener(v -> {
if (wheatView.getUserId().equals(SpUtil.getUserId() + "")) { if (wheatView.getUserId().equals(SpUtil.getUserId() + "")) {

View File

@@ -449,7 +449,7 @@ public class RoomFragment extends BaseMvpFragment<RoomPresenter, FragmentRoomBin
if (newFragment != null) { if (newFragment != null) {
// switchFragment(newFragment, mBinding.roomItem.getId(), false); // switchFragment(newFragment, mBinding.roomItem.getId(), false);
performFragmentReplacement(newFragment); performFragmentReplacementReplace(newFragment);
} else { } else {
LogUtils.e("newFragment==null"); LogUtils.e("newFragment==null");
} }
@@ -474,6 +474,47 @@ public class RoomFragment extends BaseMvpFragment<RoomPresenter, FragmentRoomBin
} }
private Fragment currentFragment = null; private Fragment currentFragment = null;
@SuppressLint("CheckResult")
private void performFragmentReplacementReplace(Fragment newFragment) {
if (getActivity() != null && getActivity() instanceof RoomActivity) {
if (newFragment instanceof RoomKtvFragment) {
Objects.requireNonNull(((RoomActivity) getActivity()).getBinding()).recyclerView.setVisibility(View.VISIBLE);
} else {
Objects.requireNonNull(((RoomActivity) getActivity()).getBinding()).recyclerView.setVisibility(View.GONE);
}
}
if (getChildFragmentManager().isDestroyed()) {
return; // 避免状态销毁后操作导致崩溃
}
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
// 动画(可选,不想动画可以删掉)
transaction.setCustomAnimations(
com.xscm.moduleutil.R.anim.a_slide_right_in,
com.xscm.moduleutil.R.anim.a_slide_left_out
);
// 使用 replace 替换当前 fragment
transaction.replace(mBinding.roomItem.getId(), newFragment, newFragment.getClass().getSimpleName());
// 如果需要保留回退栈可用 addToBackStack
// transaction.addToBackStack(newFragment.getClass().getSimpleName());
transaction.commitAllowingStateLoss();
// 更新当前 fragment 引用
currentFragment = newFragment;
// 延迟启动透明 Activity保持原逻辑
Observable.timer(1000, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(aLong -> {
if (ActivityUtils.getTopActivity() instanceof RoomActivity)
startActivity(new Intent(ActivityUtils.getTopActivity(), TransparentActivity.class));
});
}
@SuppressLint("CheckResult") @SuppressLint("CheckResult")
private void performFragmentReplacement(Fragment newFragment) { private void performFragmentReplacement(Fragment newFragment) {
@@ -730,7 +771,6 @@ public class RoomFragment extends BaseMvpFragment<RoomPresenter, FragmentRoomBin
} }
if (getActivity() instanceof RoomActivity) { if (getActivity() instanceof RoomActivity) {
RoomActivity roomActivity = (RoomActivity) getActivity();
if (!haveMe) { if (!haveMe) {
AgoraManager.getInstance().ClientRole(false); AgoraManager.getInstance().ClientRole(false);
AgoraManager.getInstance().setLocalAudioEnabled(false, SpUtil.getUserId() + ""); AgoraManager.getInstance().setLocalAudioEnabled(false, SpUtil.getUserId() + "");

View File

@@ -94,13 +94,10 @@ public class SingSongFragment extends BaseRoomFragment<SingSongPresenter, Fragme
protected String pitNumber;//当前点击的麦序 protected String pitNumber;//当前点击的麦序
protected CommonDialog commonDialog; protected CommonDialog commonDialog;
// private WheatLayoutManager wheatLayoutManager; // private WheatLayoutManager wheatLayoutManager;
private final WheatLayoutSingManager wheatLayoutSingManager = WheatLayoutSingManager.Companion.getInstance(); private WheatLayoutSingManager wheatLayoutSingManager = null;
private WheatLayoutManager wheatLayoutManager1; private WheatLayoutManager wheatLayoutManager1;
private WheatLayoutManager wheatLayoutManager2; private WheatLayoutManager wheatLayoutManager2;
private RoomPitBean roomPitBean; private RoomPitBean roomPitBean;
private PopupWindow popupWindow; private PopupWindow popupWindow;
CountDownTimer mCountDownTimer; CountDownTimer mCountDownTimer;
CountDownTimer mCountDownTimersta; CountDownTimer mCountDownTimersta;
@@ -148,6 +145,11 @@ public class SingSongFragment extends BaseRoomFragment<SingSongPresenter, Fragme
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState); super.onViewCreated(view, savedInstanceState);
// initPopupWindow(); 2025年12月24日11:18:58去掉弹框直接进行抱麦 // initPopupWindow(); 2025年12月24日11:18:58去掉弹框直接进行抱麦
// 初始化并预绘制视图 二卡八列
WheatLayoutSingManager.Companion.init(getActivity());
WheatLayoutSingManager.Companion.getInstance().setWheatData(null);
wheatLayoutSingManager = WheatLayoutSingManager.Companion.getInstance();
flexboxLayout = mBinding.flexboxLayout; flexboxLayout = mBinding.flexboxLayout;
var wheatContainer = WheatLayoutSingManager.Companion.getInstance().getRootContainer(); var wheatContainer = WheatLayoutSingManager.Companion.getInstance().getRootContainer();
flexboxLayout.addView(wheatContainer); flexboxLayout.addView(wheatContainer);