添加音频重新加载功能
This commit is contained in:
@@ -126,6 +126,8 @@ class AudioManager {
|
||||
this.readyMap = new Map();
|
||||
// 新增:首轮失败的音频集合与重试阶段标识
|
||||
this.failedLoadKeys = new Set();
|
||||
// 加载代数,用于 reloadAll 时作废旧的加载循环
|
||||
this.loadGeneration = 0;
|
||||
this.initAudios();
|
||||
}
|
||||
|
||||
@@ -141,9 +143,15 @@ class AudioManager {
|
||||
this.currentLoadingIndex = 0;
|
||||
this.failedLoadKeys.clear();
|
||||
|
||||
// 增加代数,使得旧的加载循环失效
|
||||
this.loadGeneration = (this.loadGeneration || 0) + 1;
|
||||
const currentGen = this.loadGeneration;
|
||||
|
||||
this.loadingPromise = new Promise((resolve) => {
|
||||
const finalize = () => {
|
||||
if (currentGen !== this.loadGeneration) return;
|
||||
const runRounds = (round) => {
|
||||
if (currentGen !== this.loadGeneration) return;
|
||||
// 达到最大轮次或没有失败项,收尾
|
||||
if (this.failedLoadKeys.size === 0 || round > this.maxRetryRounds) {
|
||||
this.isLoading = false;
|
||||
@@ -155,30 +163,40 @@ class AudioManager {
|
||||
this.failedLoadKeys.clear();
|
||||
debugLog(`开始第 ${round} 轮串行加载,共 ${retryKeys.length} 个`);
|
||||
|
||||
this.loadKeysSequentially(retryKeys, () => {
|
||||
// 如仍有失败项,继续下一轮;否则结束
|
||||
if (this.failedLoadKeys.size > 0 && round < this.maxRetryRounds) {
|
||||
setTimeout(() => runRounds(round + 1), this.retryRoundIntervalMs);
|
||||
} else {
|
||||
this.isLoading = false;
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
this.loadKeysSequentially(
|
||||
retryKeys,
|
||||
() => {
|
||||
if (currentGen !== this.loadGeneration) return;
|
||||
// 如仍有失败项,继续下一轮;否则结束
|
||||
if (this.failedLoadKeys.size > 0 && round < this.maxRetryRounds) {
|
||||
setTimeout(
|
||||
() => runRounds(round + 1),
|
||||
this.retryRoundIntervalMs
|
||||
);
|
||||
} else {
|
||||
this.isLoading = false;
|
||||
resolve();
|
||||
}
|
||||
},
|
||||
currentGen
|
||||
);
|
||||
};
|
||||
|
||||
// 启动第 1 轮重试(如有失败项)
|
||||
runRounds(1);
|
||||
};
|
||||
this.loadNextAudio(finalize);
|
||||
this.loadNextAudio(finalize, currentGen);
|
||||
});
|
||||
return this.loadingPromise;
|
||||
}
|
||||
|
||||
// 按自定义列表串行加载音频(避免并发过多)
|
||||
loadKeysSequentially(keys, onComplete) {
|
||||
loadKeysSequentially(keys, onComplete, gen) {
|
||||
if (gen !== undefined && gen !== this.loadGeneration) return;
|
||||
let idx = 0;
|
||||
const list = Array.from(keys);
|
||||
const next = () => {
|
||||
if (gen !== undefined && gen !== this.loadGeneration) return;
|
||||
if (idx >= list.length) {
|
||||
if (onComplete) onComplete();
|
||||
return;
|
||||
@@ -206,7 +224,8 @@ class AudioManager {
|
||||
}
|
||||
|
||||
// 串行加载下一个音频(首轮)
|
||||
loadNextAudio(onComplete) {
|
||||
loadNextAudio(onComplete, gen) {
|
||||
if (gen !== undefined && gen !== this.loadGeneration) return;
|
||||
if (this.currentLoadingIndex >= this.audioKeys.length) {
|
||||
debugLog("首轮加载遍历完成", this.currentLoadingIndex);
|
||||
if (onComplete) onComplete();
|
||||
@@ -220,7 +239,7 @@ class AudioManager {
|
||||
);
|
||||
this.createAudio(key, () => {
|
||||
setTimeout(() => {
|
||||
this.loadNextAudio(onComplete);
|
||||
this.loadNextAudio(onComplete, gen);
|
||||
}, 100);
|
||||
});
|
||||
}
|
||||
@@ -530,6 +549,38 @@ class AudioManager {
|
||||
}
|
||||
return Number((loaded / total).toFixed(2));
|
||||
}
|
||||
|
||||
|
||||
// 手动重置并重新加载所有音频(用于卡住时恢复)
|
||||
reloadAll() {
|
||||
// 1. 停止所有播放
|
||||
this.stopAll();
|
||||
|
||||
// 2. 销毁现有音频实例
|
||||
for (const audio of this.audioMap.values()) {
|
||||
try {
|
||||
audio.destroy();
|
||||
} catch (_) {}
|
||||
}
|
||||
this.audioMap.clear();
|
||||
|
||||
// 3. 重置状态
|
||||
this.readyMap.clear();
|
||||
this.failedLoadKeys.clear();
|
||||
this.allowPlayMap.clear();
|
||||
this.currentPlayingKey = null;
|
||||
this.sequenceQueue = [];
|
||||
this.sequenceIndex = 0;
|
||||
this.isSequenceRunning = false;
|
||||
|
||||
// 4. 强制重置加载锁
|
||||
this.isLoading = false;
|
||||
this.loadingPromise = null;
|
||||
this.currentLoadingIndex = 0;
|
||||
|
||||
// 5. 重新初始化 (initAudios 会自增 loadGeneration,从而终止之前的任何异步循环)
|
||||
return this.initAudios();
|
||||
}
|
||||
}
|
||||
|
||||
// 导出单例
|
||||
|
||||
@@ -66,9 +66,7 @@ const checkAudioProgress = async () => {
|
||||
if (audioInitProgress.value === 1) return resolve();
|
||||
audioTimer.value = setInterval(() => {
|
||||
const result = AudioManager.getLoadProgress();
|
||||
if (result > audioProgress.value) {
|
||||
audioProgress.value = result;
|
||||
}
|
||||
audioProgress.value = result;
|
||||
if (audioProgress.value === 1) {
|
||||
setTimeout(() => {
|
||||
audioInitProgress.value = 1;
|
||||
@@ -227,7 +225,12 @@ const goCalibration = async () => {
|
||||
mode="widthFix"
|
||||
/>
|
||||
</view>
|
||||
<text>资源加载中...</text>
|
||||
</view>
|
||||
<view>
|
||||
<text>若加载时间过长,请</text>
|
||||
<button hover-class="none" @click="AudioManager.reloadAll">
|
||||
点击这里重启
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -321,11 +324,21 @@ const goCalibration = async () => {
|
||||
width: 46rpx;
|
||||
height: 26rpx;
|
||||
}
|
||||
.audio-progress > view:nth-child(2) > text {
|
||||
width: 100%;
|
||||
.audio-progress > view:nth-child(3) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
.audio-progress > view:nth-child(3) > text {
|
||||
font-size: 22rpx;
|
||||
color: #a2a2a2;
|
||||
text-align: center;
|
||||
margin-top: 10rpx;
|
||||
line-height: 32rpx;
|
||||
}
|
||||
.audio-progress > view:nth-child(3) > button {
|
||||
font-size: 22rpx;
|
||||
color: #ffe431;
|
||||
line-height: 32rpx;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -66,7 +66,7 @@ watch(
|
||||
:onClick="toUserPage"
|
||||
:size="42"
|
||||
/>
|
||||
<view class="user-details" :onClick="toUserPage">
|
||||
<view class="user-details" @click="toUserPage">
|
||||
<view class="user-name">
|
||||
<text>{{ user.nickName }}</text>
|
||||
<image
|
||||
@@ -77,7 +77,6 @@ watch(
|
||||
</view>
|
||||
<view class="user-stats">
|
||||
<text class="level-tag level-tag-first">段位积分</text>
|
||||
<!-- <text class="level-tag level-tag-second">LV{{ user.lvl }}</text> -->
|
||||
<view class="rank-tag">
|
||||
<view
|
||||
class="rank-tag-progress"
|
||||
@@ -173,13 +172,9 @@ watch(
|
||||
}
|
||||
|
||||
.level-tag-first {
|
||||
width: 50px;
|
||||
padding: 0 10rpx;
|
||||
background: #5f51ff;
|
||||
}
|
||||
|
||||
.level-tag-second {
|
||||
width: 60rpx;
|
||||
background: #09c504;
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
.level-tag,
|
||||
@@ -191,14 +186,17 @@ watch(
|
||||
.rank-tag {
|
||||
position: relative;
|
||||
background-color: #00000038;
|
||||
width: 150rpx;
|
||||
width: 140rpx;
|
||||
overflow: hidden;
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
.rank-tag-progress {
|
||||
background: #ffa711;
|
||||
height: 100%;
|
||||
border-radius: 12px;
|
||||
width: 0;
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
|
||||
.rank-tag-text {
|
||||
@@ -211,24 +209,26 @@ watch(
|
||||
}
|
||||
|
||||
.rank-info {
|
||||
width: 70px;
|
||||
text-align: left;
|
||||
font-size: 12px;
|
||||
width: 95px;
|
||||
height: 50px;
|
||||
font-size: 24rpx;
|
||||
position: relative;
|
||||
color: #b3b3b3;
|
||||
padding-left: 8px;
|
||||
margin-left: 15rpx;
|
||||
padding-left: 12px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
.rank-info-image {
|
||||
position: absolute;
|
||||
top: -6px;
|
||||
left: -9px;
|
||||
width: 90px;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 95px;
|
||||
}
|
||||
.rank-info > text {
|
||||
text-align: center;
|
||||
word-break: keep-all;
|
||||
width: 83px;
|
||||
}
|
||||
.rank-number {
|
||||
display: block;
|
||||
|
||||
Reference in New Issue
Block a user