优化头像框加载、麦圈加载,二卡八放到对应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 均对应交友
|
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);
|
||||||
|
|||||||
@@ -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());
|
||||||
|
|||||||
@@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否主持
|
* 是否主持
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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_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>
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -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() + "")) {
|
||||||
|
|||||||
@@ -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() + "");
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user