优化头像框加载、麦圈加载,二卡八放到对应fragment加载。
This commit is contained in:
@@ -31,7 +31,7 @@ public enum QXRoomSeatViewType {
|
||||
/**
|
||||
* 酒吧
|
||||
*/
|
||||
PUB(7,"酒吧"),
|
||||
PUB(11,"酒吧"),
|
||||
/**
|
||||
* 酒吧
|
||||
*/
|
||||
|
||||
@@ -15,7 +15,7 @@ enum class RoomType(
|
||||
DATING("交友", 1,3, 4, 8), // 1、3、4、8 均对应交友
|
||||
BLACK_ROOM("小黑屋", 6),
|
||||
JUKEBOX("点唱", 9),
|
||||
PUB_ROOM("酒吧", 7),
|
||||
PUB_ROOM("酒吧", 11),
|
||||
PRIVATE_ROOM("酒吧交友小屋", 12),
|
||||
MUTUAL_ENTERTAINMENT("互娱", 7),
|
||||
SIGN_CONTRACT("签约", 10);
|
||||
|
||||
@@ -107,7 +107,7 @@ public class AgoraManager {
|
||||
|
||||
private static List<Music> musicList;
|
||||
private static boolean isBjMusic = false;
|
||||
private static List<SoundLevelUpdateListener> soundLevelUpdateListeners = new CopyOnWriteArrayList<>();
|
||||
private List<SoundLevelUpdateListener> soundLevelUpdateListeners = new CopyOnWriteArrayList<>();
|
||||
private static ChannelMediaOptions options;
|
||||
private static RtcConnection connection;
|
||||
private String pkRoomId = "";
|
||||
@@ -130,8 +130,6 @@ public class AgoraManager {
|
||||
private final Handler uiHandler = new Handler(Looper.getMainLooper());
|
||||
private long lastDispatchTime = 0;
|
||||
|
||||
// 缓存本次声网回调的音量结果
|
||||
private final Map<String, Integer> volumeCache = new HashMap<>();
|
||||
public void setLastRoomId(String value) {
|
||||
lastRoomId = value;
|
||||
}
|
||||
@@ -212,7 +210,7 @@ public class AgoraManager {
|
||||
try {
|
||||
rtcEngine.setAudioProfile(Constants.AUDIO_PROFILE_MUSIC_HIGH_QUALITY_STEREO,
|
||||
Constants.AUDIO_SCENARIO_GAME_STREAMING);
|
||||
rtcEngine.enableAudioVolumeIndication(100, 3, false);
|
||||
rtcEngine.enableAudioVolumeIndication(200, 3, true);
|
||||
rtcEngine.setClientRole(Constants.CLIENT_ROLE_BROADCASTER);
|
||||
rtcEngine.muteLocalAudioStream(true); // 默认静音
|
||||
rtcEngine.muteAllRemoteAudioStreams(false); // 监听远端的音频
|
||||
@@ -584,6 +582,7 @@ public class AgoraManager {
|
||||
if (soundLevelUpdateListeners.isEmpty()) return;
|
||||
|
||||
for (Map.Entry<String, Integer> entry : volumeSnapshot.entrySet()) {
|
||||
|
||||
for (SoundLevelUpdateListener listener : soundLevelUpdateListeners) {
|
||||
if (listener != null) {
|
||||
listener.onRemoteSoundLevelUpdate(entry.getKey(), entry.getValue());
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
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;
|
||||
|
||||
@@ -16,21 +14,14 @@ 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;
|
||||
@@ -40,11 +31,8 @@ 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;
|
||||
|
||||
@@ -57,9 +45,9 @@ import okhttp3.ResponseBody;
|
||||
|
||||
|
||||
public class AvatarFrameView extends FrameLayout {
|
||||
private PlaybackManager playbackManager;
|
||||
|
||||
private boolean isMute = false;
|
||||
|
||||
public void setMute(boolean b) {
|
||||
this.isMute = b;
|
||||
}
|
||||
@@ -68,10 +56,7 @@ public class AvatarFrameView extends FrameLayout {
|
||||
|
||||
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<PlayItem> playQueue = new LinkedBlockingQueue<>();
|
||||
|
||||
private boolean isPlaying = false;
|
||||
// 添加销毁标记
|
||||
@@ -79,8 +64,6 @@ public class AvatarFrameView extends FrameLayout {
|
||||
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);
|
||||
|
||||
@@ -101,25 +84,10 @@ public class AvatarFrameView extends FrameLayout {
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -130,186 +98,51 @@ public class AvatarFrameView extends FrameLayout {
|
||||
}
|
||||
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;
|
||||
|
||||
// 处理播放项目
|
||||
public void setSource(String url, int type2) {
|
||||
// 添加到播放队列
|
||||
PlayItem item = new PlayItem(url, type2);
|
||||
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();
|
||||
});
|
||||
Logger.d("AvatarFrameView", "Added to queue, queue size: url: " + url);
|
||||
}
|
||||
|
||||
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) {
|
||||
if (mBinding != 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) {
|
||||
if (mBinding != 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) {
|
||||
if (mBinding != 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;
|
||||
@@ -330,12 +163,6 @@ public class AvatarFrameView extends FrameLayout {
|
||||
@Override
|
||||
public void onFailure(Call call, IOException e) {
|
||||
LogUtils.e("MP4下载失败: " + e.toString());
|
||||
mainHandler.post(() -> {
|
||||
// 检查是否已销毁
|
||||
if (!isDestroyed) {
|
||||
onPlaybackComplete();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 更简单的优化版本
|
||||
@@ -371,55 +198,29 @@ public class AvatarFrameView extends FrameLayout {
|
||||
|
||||
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()) {
|
||||
LogUtils.e("有缓存:" + file.exists() + "====" + file.getAbsolutePath());
|
||||
@@ -427,7 +228,6 @@ public class AvatarFrameView extends FrameLayout {
|
||||
} else {
|
||||
LogUtils.w(TAG, "有缓存2222222222222");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -436,13 +236,11 @@ public class AvatarFrameView extends FrameLayout {
|
||||
// 双重检查确保组件未被销毁
|
||||
if (isDestroyed) {
|
||||
LogUtils.w(TAG, "Attempt to play MP4 file after view destroyed");
|
||||
onPlaybackComplete();
|
||||
return;
|
||||
}
|
||||
|
||||
if (mBinding == null || mBinding.playView == null) {
|
||||
if (mBinding == null) {
|
||||
LogUtils.w(TAG, "PlayView is null");
|
||||
onPlaybackComplete();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -459,21 +257,17 @@ public class AvatarFrameView extends FrameLayout {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -496,7 +290,6 @@ public class AvatarFrameView extends FrameLayout {
|
||||
svgaSurface.stopAnimation();
|
||||
svgaSurface.clearAnimation();
|
||||
svgaSurface.setImageDrawable(null);
|
||||
onPlaybackComplete();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -506,11 +299,8 @@ public class AvatarFrameView extends FrameLayout {
|
||||
|
||||
@Override
|
||||
public void onFinished() {
|
||||
// if (isDestroyed) return;
|
||||
if (mType == 1) { // 循环播放
|
||||
// 继续循环播放
|
||||
} else {
|
||||
onPlaybackComplete();
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -523,10 +313,6 @@ public class AvatarFrameView extends FrameLayout {
|
||||
svgaSurface.startAnimation();
|
||||
} catch (Exception e) {
|
||||
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.setImageDrawable(null);
|
||||
}
|
||||
if (svgaSurface2 != null) {
|
||||
svgaSurface2.stopAnimation();
|
||||
svgaSurface2.clearAnimation();
|
||||
svgaSurface.setImageDrawable(null);
|
||||
}
|
||||
// 增加空值检查
|
||||
if (mBinding != null && mBinding.playView != null) {
|
||||
if (mBinding != null) {
|
||||
mBinding.playView.stopPlay();
|
||||
}
|
||||
}
|
||||
@@ -566,16 +347,7 @@ public class AvatarFrameView extends FrameLayout {
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
||||
});
|
||||
// 设置循环次数
|
||||
@@ -588,21 +360,16 @@ public class AvatarFrameView extends FrameLayout {
|
||||
} 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));
|
||||
handleSVGAComplete(videoItem, url);
|
||||
} else {
|
||||
handleSVGAComplete(videoItem, url);
|
||||
}
|
||||
@@ -610,32 +377,16 @@ public class AvatarFrameView extends FrameLayout {
|
||||
|
||||
@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);
|
||||
|
||||
@@ -653,7 +404,6 @@ public class AvatarFrameView extends FrameLayout {
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "Error loading SVGA: " + e.getMessage());
|
||||
isPlaying = false;
|
||||
playNextFromQueue();
|
||||
}
|
||||
|
||||
svgaSurface.setVisibility(View.VISIBLE);
|
||||
@@ -683,7 +433,6 @@ public class AvatarFrameView extends FrameLayout {
|
||||
@Override
|
||||
public void onFinished() {
|
||||
isPlaying = false;
|
||||
playNextFromQueue();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -693,7 +442,6 @@ public class AvatarFrameView extends FrameLayout {
|
||||
@Override
|
||||
public void onError() {
|
||||
isPlaying = false;
|
||||
playNextFromQueue();
|
||||
}
|
||||
});
|
||||
} 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);
|
||||
|
||||
|
||||
@@ -750,39 +497,7 @@ public class AvatarFrameView extends FrameLayout {
|
||||
*/
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -791,31 +506,16 @@ public class AvatarFrameView extends FrameLayout {
|
||||
private void performUICleanup() {
|
||||
try {
|
||||
// 停止并清理播放器
|
||||
if (mBinding != null && mBinding.playView != null) {
|
||||
if (mBinding != 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();
|
||||
@@ -834,86 +534,23 @@ public class AvatarFrameView extends FrameLayout {
|
||||
*/
|
||||
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<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 {
|
||||
String url;
|
||||
int type;
|
||||
@@ -923,167 +560,4 @@ public class AvatarFrameView extends FrameLayout {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ import com.xscm.moduleutil.event.RoomFaceEvent;
|
||||
import com.xscm.moduleutil.interfaces.IBaseWheat;
|
||||
import com.xscm.moduleutil.interfaces.SoundLevelUpdateListener;
|
||||
import com.xscm.moduleutil.rtc.AgoraManager;
|
||||
import com.xscm.moduleutil.utils.ImageUtils;
|
||||
import com.xscm.moduleutil.utils.SpUtil;
|
||||
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 RoomPitBean pitBean;//麦位数据
|
||||
|
||||
public String roomId;//房间id
|
||||
|
||||
CountDownTimer mCountDownTimer;
|
||||
@@ -82,17 +84,14 @@ public abstract class BaseWheatView extends ConstraintLayout implements IBaseWhe
|
||||
public ImageView iv_on_line;
|
||||
private boolean showGiftAnim = true;//显示麦位动画
|
||||
private ImageView iv_tag_type;
|
||||
|
||||
// 当前音量监听器,用于防止重复添加
|
||||
private SoundLevelUpdateListener currentSoundLevelListener;
|
||||
|
||||
private TextView tv_zhul;
|
||||
|
||||
private SVGAParser mParser;
|
||||
|
||||
private final SVGAParser parser = new SVGAParser(CommonAppContext.getInstance());
|
||||
private String micCycle = "";
|
||||
|
||||
public boolean isMentorShip = false;
|
||||
private SoundLevelUpdateListener soundLevelUpdateListener;
|
||||
|
||||
public BaseWheatView(Context context) {
|
||||
this(context, null, 0);
|
||||
@@ -112,6 +111,7 @@ public abstract class BaseWheatView extends ConstraintLayout implements IBaseWhe
|
||||
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);
|
||||
@@ -192,8 +192,15 @@ public abstract class BaseWheatView extends ConstraintLayout implements IBaseWhe
|
||||
iv_on_line.setVisibility(GONE);
|
||||
}
|
||||
|
||||
|
||||
parser.decodeFromAssets("mic.svga", new SVGAParser.ParseCompletion() {
|
||||
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) {
|
||||
@@ -206,6 +213,27 @@ public abstract class BaseWheatView extends ConstraintLayout implements IBaseWhe
|
||||
Log.e("SVGA", "解析 ripple.svga 失败");
|
||||
}
|
||||
});
|
||||
} 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 失败");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
setPitData(bean);
|
||||
|
||||
@@ -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
|
||||
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;
|
||||
|
||||
boolean nowSpeaking = soundLevel > 0;
|
||||
|
||||
updateSpeakingState(nowSpeaking);
|
||||
}
|
||||
|
||||
@@ -290,9 +323,13 @@ public abstract class BaseWheatView extends ConstraintLayout implements IBaseWhe
|
||||
if (mIvRipple == null)
|
||||
return;
|
||||
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
|
||||
public void onError() {}
|
||||
public void onError() {
|
||||
}
|
||||
});
|
||||
} catch (MalformedURLException ignored) {}
|
||||
} catch (MalformedURLException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
public void setCharm(String charm) {
|
||||
@@ -423,6 +462,7 @@ public abstract class BaseWheatView extends ConstraintLayout implements IBaseWhe
|
||||
showGiftAnim = false;
|
||||
releaseCountDownTimer();
|
||||
super.onDetachedFromWindow();
|
||||
mParser = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -742,7 +782,6 @@ public abstract class BaseWheatView extends ConstraintLayout implements IBaseWhe
|
||||
mIvFace.addData(new FaceBean(roomRollModel.getNumber(), 2));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 是否主持
|
||||
*
|
||||
|
||||
@@ -74,7 +74,7 @@ public class RoomKtvWheatView extends BaseWheatView {
|
||||
sex = bean.getSex();
|
||||
if (isOn()) {
|
||||
//开启声浪
|
||||
if (mCharmView != null) {
|
||||
if (mIvRipple != null) {
|
||||
mIvRipple.stopAnimation(true);
|
||||
mIvRipple.setVisibility(VISIBLE);
|
||||
}
|
||||
@@ -103,12 +103,7 @@ public class RoomKtvWheatView extends BaseWheatView {
|
||||
mIvTagBoss.setVisibility(VISIBLE);
|
||||
ImageUtils.loadRes(isLocked() ? R.mipmap.room_ic_wheat_default_suo : R.mipmap.room_ic_wheat_default, mRiv);
|
||||
} 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);
|
||||
// ImageUtils.loadRes(isLocked() ? R.mipmap.room_ic_wheat_default_suo : R.mipmap.room_ic_wheat_default, mRiv);
|
||||
}
|
||||
if (isMute()) {
|
||||
ImageUtils.loadRes(R.mipmap.room_microphone_off, mIvSex);
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -10,18 +10,6 @@
|
||||
android:layout_width="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
|
||||
android:id="@+id/play_view"
|
||||
android:layout_width="0dp"
|
||||
@@ -29,8 +17,6 @@
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
|
||||
/>
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</layout>
|
||||
@@ -96,9 +96,7 @@ open class Application : CommonAppContext() {
|
||||
configureLeakCanary()
|
||||
|
||||
|
||||
// 初始化并预绘制视图 二卡八列
|
||||
WheatLayoutSingManager.init(this)
|
||||
WheatLayoutSingManager.getInstance().setWheatData(null)
|
||||
|
||||
|
||||
// 默认情况下,SVGA 内部不会输出任何 log,所以需要手动设置为 true
|
||||
SVGALogger.setLogEnabled(false)
|
||||
|
||||
@@ -484,6 +484,7 @@ public class RoomAuctionFragment extends BaseMvpFragment<RoomAuctionPresenterTow
|
||||
|
||||
|
||||
private void getTextView() {
|
||||
try {
|
||||
int defaultColor = ContextCompat.getColor(requireContext(), com.xscm.moduleutil.R.color.color_0DFFB9); // 亲密拍默认颜色(绿色)
|
||||
int selectedColor = ContextCompat.getColor(requireContext(), com.xscm.moduleutil.R.color.color_white); // 选中颜色(白色)
|
||||
int clickedColor = ContextCompat.getColor(requireContext(), com.xscm.moduleutil.R.color.color_BB8BE2); // 真爱拍选中颜色(蓝色)
|
||||
@@ -505,6 +506,9 @@ public class RoomAuctionFragment extends BaseMvpFragment<RoomAuctionPresenterTow
|
||||
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 -> {
|
||||
if (wheatView.getUserId().equals(SpUtil.getUserId() + "")) {
|
||||
// 判断 wheatView2 是否有人
|
||||
|
||||
@@ -449,7 +449,7 @@ public class RoomFragment extends BaseMvpFragment<RoomPresenter, FragmentRoomBin
|
||||
|
||||
if (newFragment != null) {
|
||||
// switchFragment(newFragment, mBinding.roomItem.getId(), false);
|
||||
performFragmentReplacement(newFragment);
|
||||
performFragmentReplacementReplace(newFragment);
|
||||
} else {
|
||||
LogUtils.e("newFragment==null");
|
||||
}
|
||||
@@ -474,6 +474,47 @@ public class RoomFragment extends BaseMvpFragment<RoomPresenter, FragmentRoomBin
|
||||
}
|
||||
|
||||
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")
|
||||
private void performFragmentReplacement(Fragment newFragment) {
|
||||
@@ -730,7 +771,6 @@ public class RoomFragment extends BaseMvpFragment<RoomPresenter, FragmentRoomBin
|
||||
}
|
||||
|
||||
if (getActivity() instanceof RoomActivity) {
|
||||
RoomActivity roomActivity = (RoomActivity) getActivity();
|
||||
if (!haveMe) {
|
||||
AgoraManager.getInstance().ClientRole(false);
|
||||
AgoraManager.getInstance().setLocalAudioEnabled(false, SpUtil.getUserId() + "");
|
||||
|
||||
@@ -94,13 +94,10 @@ public class SingSongFragment extends BaseRoomFragment<SingSongPresenter, Fragme
|
||||
protected String pitNumber;//当前点击的麦序
|
||||
protected CommonDialog commonDialog;
|
||||
// private WheatLayoutManager wheatLayoutManager;
|
||||
private final WheatLayoutSingManager wheatLayoutSingManager = WheatLayoutSingManager.Companion.getInstance();
|
||||
private WheatLayoutSingManager wheatLayoutSingManager = null;
|
||||
private WheatLayoutManager wheatLayoutManager1;
|
||||
private WheatLayoutManager wheatLayoutManager2;
|
||||
|
||||
|
||||
private RoomPitBean roomPitBean;
|
||||
|
||||
private PopupWindow popupWindow;
|
||||
CountDownTimer mCountDownTimer;
|
||||
CountDownTimer mCountDownTimersta;
|
||||
@@ -148,6 +145,11 @@ public class SingSongFragment extends BaseRoomFragment<SingSongPresenter, Fragme
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
// initPopupWindow(); 2025年12月24日11:18:58,去掉弹框,直接进行抱麦
|
||||
|
||||
// 初始化并预绘制视图 二卡八列
|
||||
WheatLayoutSingManager.Companion.init(getActivity());
|
||||
WheatLayoutSingManager.Companion.getInstance().setWheatData(null);
|
||||
wheatLayoutSingManager = WheatLayoutSingManager.Companion.getInstance();
|
||||
flexboxLayout = mBinding.flexboxLayout;
|
||||
var wheatContainer = WheatLayoutSingManager.Companion.getInstance().getRootContainer();
|
||||
flexboxLayout.addView(wheatContainer);
|
||||
|
||||
Reference in New Issue
Block a user