HarmonyOS鸿蒙Next中使用AVPlayer播放音频时,无法暂停
HarmonyOS鸿蒙Next中使用AVPlayer播放音频时,无法暂停
//音频播放器
async AVPlayer() {
const avplayer = await media.createAVPlayer()
const context = getContext(this) as common.UIAbilityContext;
try {
const fileDescriptor = await context.resourceManager.getRawFd(VideoSources[this.Params.id][2]);
if (!fileDescriptor.fd) {
throw new Error('Failed to load audio file descriptor');
}
avplayer.fdSrc = {
fd: fileDescriptor.fd,
offset: fileDescriptor.offset,
length: -1
};
avplayer.on('stateChange', (state) => {
switch (state) {
case 'initialized':
avplayer.prepare()
break;
case 'prepared':
avplayer.play()
break;
case 'playing':
if (this.runningData.Running_State === 'pause') {
avplayer.pause()
} else if (this.runningData.Running_State === 'end') {
avplayer.stop()
avplayer.release()
avplayer.off('stateChange')
}
break;
case 'paused':
if (this.runningData.Running_State === 'start') {
avplayer.play()
} else if (this.runningData.Running_State === 'end') {
avplayer.stop()
avplayer.release()
avplayer.off('stateChange')
}
break;
case 'completed':
avplayer.play()
break;
default:
break;
}
})
avplayer.on('error', (err) => {
console.error(`播放错误: ${err.code}, ${err.message}`);
avplayer.reset();
});
} catch (error) {
console.log('初始化播放器失败', JSON.stringify(error))
}
}
以上代码可以实现在进入页面后循环播放音乐,但是无法受到this.runningData.Running_State的控制而暂停,请问是什么原因?
更多关于HarmonyOS鸿蒙Next中使用AVPlayer播放音频时,无法暂停的实战教程也可以访问 https://www.itying.com/category-93-b0.html
需要通过触发stateChange才能暂停播放,可以参考下这个示例:
import media from '@ohos.multimedia.media';
import { BusinessError } from '@ohos.base';
import common from '@ohos.app.ability.common';
// 音频播放
export class AVPlayerDemo {
public flag: number = 1;
public static avPlayerCom: media.AVPlayer;
public static avFileDescriptorCom: media.AVFileDescriptor;
public curAudioPath: string = '';
public avFileDescriptor4: media.AVFileDescriptor | undefined = undefined;
public isLoop: boolean = false;
private avPlayer: media.AVPlayer | null = null;
// 注册avplayer回调函数
setAVPlayerCallback(avPlayer: media.AVPlayer): void {
// seek操作结果回调函数
avPlayer.on('seekDone', (seekDoneTime: number) => {
console.info(`AVPlayer seek succeeded, seek time is ${seekDoneTime}`);
})
// error回调监听函数,当avPlayer在操作过程中出现错误时调用 reset接口触发重置流程
avPlayer.on('error', (err: BusinessError) => {
console.error(`Invoke avPlayer failed, code is ${err.code}, message is ${err.message}`);
avPlayer.reset(); // 调用reset重置资源,触发idle状态
})
// 状态机变化回调函数
avPlayer.on('stateChange', async (state: string, _: media.StateChangeReason) => {
switch (state) {
case 'idle': // 成功调用reset接口后触发该状态机上报
console.info('AVPlayer state idle called.');
avPlayer.release(); // 调用release接口销毁实例对象
break;
case 'initialized': // avplayer 设置播放源后触发该状态上报
console.info('AVPlayer state initialized called.');
avPlayer.prepare();
break;
case 'prepared': // prepare调用成功后上报该状态机
console.info('AVPlayer state prepared called.');
avPlayer.play(); // 调用播放接口开始播放
break;
case 'playing': // play成功调用后触发该状态机上报
console.info('AVPlayer state playing called.');
break;
case 'paused': // pause成功调用后触发该状态机上报
console.info('AVPlayer state paused called.');
break;
case 'completed': // 播放结束后触发该状态机上报
console.info('AVPlayer state completed called.');
if (this.isLoop) {
avPlayer.play()
} else {
avPlayer.stop(); //调用播放结束接口
}
break;
case 'stopped': // stop接口成功调用后触发该状态机上报
console.info('AVPlayer state stopped called.');
avPlayer.reset(); // 调用reset接口初始化avplayer状态
break;
case 'released':
console.info('AVPlayer state released called.');
break;
default:
console.info('AVPlayer state unknown called.');
break;
}
})
}
async avPlayerUrlDemo(): Promise<void> {
// 创建avPlayer实例对象
try {
this.avPlayer = await media.createAVPlayer();
this.avPlayer.audioRendererInfo
// 创建状态机变化回调函数
await this.setAVPlayerCallback(this.avPlayer);
// 通过UIAbilityContext获取沙箱地址filesDir,以Stage模型为例
const context = getContext(this) as common.UIAbilityContext;
let fileDescriptor = await context.resourceManager.getRawFd('AV_1739446770000.m4a');
let avFileDescriptor: media.AVFileDescriptor =
{ fd: fileDescriptor.fd, offset: fileDescriptor.offset, length: fileDescriptor.length };
// 测试可以播放
this.avPlayer.fdSrc = avFileDescriptor;
AVPlayerDemo.avFileDescriptorCom = avFileDescriptor;
} catch (e) {
}
}
async StopPlayer(): Promise<void> {
try {
this.avPlayer?.stop();
} catch (e) {
}
}
async PausePlayer(): Promise<void> {
try {
this.avPlayer?.pause();
} catch (e) {
}
}
async PauseedPlayer(): Promise<void> {
try {
this.avPlayer?.play();
} catch (e) {
}
}
}
@Entry
@Component
export struct AVPlayerSimple {
avPlayer = new AVPlayerDemo();
build() {
Column() {
Button('播放音频')
.onClick(() => {
this.avPlayer.avPlayerUrlDemo().then(() => {
});
})
.width('100')
.height('100')
Button('暂停播放')
.onClick(() => {
this.avPlayer.PausePlayer()
})
.width('100')
.height('100')
Button('继续播放')
.onClick(() => {
this.avPlayer.PauseedPlayer()
})
.width('100')
.height('100')
Button('停止播放')
.onClick(() => {
this.avPlayer.StopPlayer().then(() => {
});
})
.width('100')
.height('100')
Button('循环播放')
.onClick(() => {
this.avPlayer.isLoop = true;
})
.width('100')
.height('100')
}
.width('200')
.height('200')
}
}
更多关于HarmonyOS鸿蒙Next中使用AVPlayer播放音频时,无法暂停的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
使用AVPlayer播放音频(ArkTS): https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/using-avplayer-for-playback
你的暂停控制逻辑依赖stateChange事件触发,但该事件仅在播放器内部状态变化时才会回调。当外部变量this.runningData.Running_State改变时(例如用户点击暂停按钮),若未主动触发播放器的状态变化(如调用pause()或play()),则监听函数不会执行。
避免在stateChange回调中依赖外部变量,改为直接通过用户操作(如按钮点击)触发控制方法:
// 在UI事件中直接调用暂停
pauseAudio() {
if (this.avPlayer && this.avPlayer.state === 'playing') {
this.avPlayer.pause();
this.runningData.Running_State = 'pause'; // 更新状态
}
}
使用箭头函数或绑定this,确保回调中访问的是最新状态:
avplayer.on('stateChange', (state) => {
// 使用箭头函数保留外层this作用域
if (this.runningData.Running_State === 'pause' && state === 'playing') {
avplayer.pause();
}
});
在关键节点(如播放开始前)主动检查运行状态:
case 'prepared':
if (this.runningData.Running_State === 'start') {
avplayer.play();
} else if (this.runningData.Running_State === 'pause') {
avplayer.pause(); // 直接响应暂停状态
}
break;
修正completed状态处理,避免无效播放:
case 'completed':
if (this.runningData.Running_State !== 'end') {
avplayer.seek(0); // 回到开头
avplayer.play();
}
break;
找HarmonyOS工作还需要会Flutter的哦,有需要Flutter教程的可以学学大地老师的教程,很不错,B站免费学的哦:https://www.bilibili.com/video/BV1S4411E7LY/?p=17
我问一下 runningData这是一个对象数据你有用@Trace修饰Running_state吗,不然UI监听不到的,也就不会改变状态
Running_state可以控制Video组件暂停,可以控制暂停弹窗,却无法控制音乐暂停,
在HarmonyOS Next中,AVPlayer暂停失败通常与状态管理有关。AVPlayer需处于prepared、started或paused状态才能响应pause()方法。若状态为stopped、idle或error,调用pause()将无效。检查播放器当前状态,确保在正确状态下执行暂停操作。同时确认音频资源已正确加载且未发生解码异常。可通过状态监听器实时追踪状态变更。
从代码分析,暂停功能失效的主要原因是状态管理逻辑存在时序问题。在playing
状态中检查this.runningData.Running_State
时,该状态可能尚未更新。
具体问题:
- 状态监听器仅在状态变更时触发,但
this.runningData.Running_State
可能在非状态变更期间被修改 - 当播放器进入
playing
状态后,除非再次触发状态变更,否则不会重新执行状态判断逻辑
建议优化方案:
- 将状态控制逻辑从状态监听器中抽离,通过独立方法控制播放器
- 在修改
this.runningData.Running_State
时直接调用对应的播放器控制方法
示例修改:
// 添加控制方法
controlPlayback() {
if (this.runningData.Running_State === 'start' && this.avplayer.state === 'paused') {
this.avplayer.play();
} else if (this.runningData.Running_State === 'pause' && this.avplayer.state === 'playing') {
this.avplayer.pause();
} else if (this.runningData.Running_State === 'end') {
this.avplayer.stop();
this.avplayer.release();
}
}
// 在runningData状态变更时调用此方法
同时简化状态监听器,仅处理必要的状态转换,避免在监听器中嵌入过多业务逻辑。这样可确保状态变更能及时响应外部控制。