HarmonyOS开发案例:【音乐播放器】

介绍

使用ArkTS语言实现了一个简易的音乐播放器应用,主要包含以下功能:

  1. 播放应用中的音频资源文件,并可进行上一曲、下一曲、播放、暂停、切换播放模式(顺序播放、单曲循环、随机播放)等操作。
  2. 结合后台任务管理模块,实现熄屏后继续播放音频。

相关概念

  • [AVPlayer]:AVPlayer主要工作是将Audio/Video媒体资源转码为可供渲染的图像和可听见的音频模拟信号,并通过输出设备进行播放,同时对播放任务进行管理,包括开始播放、暂停播放、停止播放、释放资源、设置音量、跳转播放位置、获取轨道信息等功能控制。
  • [后台任务管理]:针对应用或业务模块处于后台(无可见界面)时,有需要继续执行或者后续执行的业务,可基于业务类型,申请短时任务延迟挂起或者长时任务避免进入挂起状态;如后台播放音乐可使用长时任务避免进入挂起状态。
  • 鸿蒙开发指导文档:gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md点击或者复制转到。

约束与限制

  1. 本篇Codelab部分能力依赖于系统API,需下载full-SDK并替换DevEco Studio自动下载的public-SDK。具体操作可参考指南[《如何替换full-SDK》]。
  2. 本篇Codelab使用的部分API仅系统应用可用,需要提升应用等级。

环境搭建

软件要求

  • [DevEco Studio]版本:DevEco Studio 3.1 Release。
  • OpenHarmony SDK版本:API version 9。

硬件要求

  • 开发板类型:[润和RK3568开发板]。
  • OpenHarmony系统:3.2 Release。

环境搭建

完成本篇Codelab我们首先要完成开发环境的搭建,本示例以RK3568开发板为例,参照以下步骤进行:

  1. [获取OpenHarmony系统版本]:标准系统解决方案(二进制)。以3.2 Release版本为例:

  2. 搭建烧录环境。

    1. [完成DevEco Device Tool的安装]
    2. [完成RK3568开发板的烧录]
  3. 搭建开发环境。

    1. 开始前请参考[工具准备],完成DevEco Studio的安装和开发环境配置。
    2. 开发环境配置完成后,请参考[使用工程向导]创建工程(模板选择“Empty Ability”)。
    3. 工程创建完成后,选择使用[真机进行调测]。
    4. HarmonyOS与OpenHarmony鸿蒙文档籽料:mau123789是v直接拿

搜狗高速浏览器截图20240326151450.png

代码结构解读

本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在gitee中提供。

├──entry/src/main/ets               // 代码区
│  ├──common              
│  │  ├──constants                   
│  │  │  └──CommonConstants.ets     // 公共常量
│  │  ├──model                   
│  │  │  └──PlayBarModel            // 播放栏数据模型
│  │  └──utils
│  │     ├──AvSessionUtil.ets  	    // 媒体会话工具类	
│  │     ├──BackgroundTaskUtil.ets  // 后台任务工具类
│  │     ├──CommonUtil.ets  	    // 公共工具类	
│  │     ├──GlobalContext.ets  	    // 公共工具类	
│  │     ├──Logger.ets              // 日志类          
│  │     └──ResourceManagerUtil.ets // 资源管理工具类
│  ├──controller           
│  │  ├──AudioPlayerController.ets  // 音乐播放器控制器
│  │  └──PlayBarController.ets      // 播放栏控制器
│  ├──entryability                    
│  │  └──EntryAbility.ets           // 程序入口类
│  ├──pages                          
│  │  ├──AudioStartUp.ets           // 启动页
│  │  ├──MusicList.ets              // 歌单页
│  │  └──Play.ets                   // 播放页
│  ├──view                         
│  │  ├──MusicCardView.ets          // 播放卡片模块
│  │  ├──MusicView.ets              // 歌单音乐模块
│  │  ├──PlayBarView.ets            // 播放控制模块
│  │  ├──PlayListDialogView.ets     // 弹窗模块
│  │  ├──PlayListMusicView.ets      // 弹窗音乐模块
│  │  └──ProgressView.ets           // 播放页
│  └──viewmodel  
│     ├──MusicItem.ets              // 音乐类
│     └──MusicViewModel.ets         // 歌单音乐模型
└──entry/src/main/resources         // 应用资源目录

实现音频播放

本案例使用播放管理类AVPlayer,实现应用内音频资源的播放,并可进行上一曲、下一曲、播放、暂停、切换播放模式(顺序播放、单曲循环、随机播放)等操作。

使用AVPlayer播放器,需要先创建一个AVPlayer实例。在AudioPlayerController中使用createAVPlayer方法完成音频播放实例的创建。

// AudioPlayerController.ets
initAudioPlayer() {media.createAVPlayer((error, video) => {if (video === undefined) {this.avPlayer = video;Logger.error(TAG, `createAVPlayer fail, error: ${error}`);} else {this.avPlayer = video;Logger.info(TAG, 'createAVPlayer success');}});
}

根据业务需要设置监听事件,搭配播放场景使用。

// AudioPlayerController.ets
// 注册AVPlayer回调函数
setEventCallBack() {...// 状态变更回调函数。this.avPlayer.on('stateChange', async (state) => {...switch (state) {case StateEvent.IDLE: // 调用reset成功后触发此状态。...case StateEvent.INITIALIZED: // 设置播放源触发此状态。...case StateEvent.PREPARED:...case StateEvent.PLAYING:...case StateEvent.COMPLETED:...default:Logger.error('unknown state: ' + state);break;}})
}  

设置音频资源,AVPlayer进入initialized状态。在initialized状态回调中,调用prepare方法,准备播放,AVPlayer进入prepared状态。

// AudioPlayerController.ets
async play(src: media.AVFileDescriptor, seekTo: number) {Logger.info(TAG, 'audioPlayer play');...// 设置播放源this.avPlayer.fdSrc = src;
}setEventCallBack() {...this.avPlayer.on('stateChange', async (state) => {...switch (state) {...case StateEvent.INITIALIZED:// 设置播放源后进入initialized状态Logger.info(TAG, 'state initialized called');this.avPlayerState = PlayerState.INITIALIZED;this.avPlayer.prepare().then(() => {Logger.info(TAG, 'prepare success');}, (err) => {Logger.error(TAG, `prepare failed,error message is: ${err.message}`);})break;...}})
}

AVPlayer进入prepared状态,可进行音频播控操作。包括播放play()、跳转至指定位置播放seek()、暂停pause()、停止stop()等操作。

// AudioPlayerController.ets
setEventCallBack() {...this.avPlayer.on('stateChange', async (state) => {...switch (state) {...case StateEvent.PREPARED:Logger.info(TAG, 'state prepared called');this.avPlayer.play();break;...}})
}

切换歌曲播放时,需调用reset()重置资源。此时AVPlayer重新进入idle状态,允许更换资源。

// AudioPlayerController.ets
async play(src: media.AVFileDescriptor, seekTo: number) {...if (this.avPlayerState === PlayerState.INITIALIZED) {await this.avPlayer.reset();Logger.info(TAG, 'play reset success');}...
}

 说明:  只能在initialized/prepared/playing/paused/complete/stopped/error状态调用reset()。

调用release()销毁实例,AVPlayer进入released状态,退出播放。

// AudioPlayerController.ets
async release() {Logger.info(TAG, 'audioPlayer release');if (typeof (this.avPlayer) !== 'undefined') {if (this.timeId === CommonConstants.DEFAULT_TIME_ID) {clearInterval(this.timeId);}await this.avPlayer.release();this.avPlayer = undefined;}
}

实现熄屏后播放

通过后台任务管理模块申请长时任务,可避免设备熄屏后,应用进入挂起状态。

首先在module.json5文件中配置长时任务权限和后台模式类型。

"module": {..."abilities": [{..."backgroundModes": ["audioPlayback"],...}],"requestPermissions": [{"name": "ohos.permission.KEEP_BACKGROUND_RUNNING"}],
}

在播放音乐时,申请长时任务。这样在应用切换至后台或设备熄屏后,仍可以继续播放音乐。

// BackgroundTaskUtil.ets
import wantAgent from '@ohos.app.ability.wantAgent';
import backgroundTaskManager from '@ohos.resourceschedule.backgroundTaskManager';
...
export class BackgroundTaskUtil {...public static startContinuousTask(context: Context) {if (context === undefined) {Logger.info(TAG, 'startContinuousTask fail,context is empty.');return;}let wantAgentInfo = {// 点击通知后需要执行的动作wants: [{bundleName: CommonConstants.BUNDLE_NAME,abilityName: CommonConstants.ABILITY_NAME}],// 单击通知后的动作类型operationType: wantAgent.OperationType.START_ABILITY,// 用户定义的私有属性requestCode: CommonConstants.BACKGROUND_REQUEST_CODE} as wantAgent.WantAgentInfo;// 通过WanAgent模块的方法获取WanAgent对象wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj) => {try {backgroundTaskManager.startBackgroundRunning(context, backgroundTaskManager.BackgroundMode.AUDIO_PLAYBACK,wantAgentObj).then(() => {Logger.info(TAG, 'startBackgroundRunning succeeded');}).catch((err: Error) => {Logger.error(TAG, 'startBackgroundRunning failed, Cause: ' + JSON.stringify(err));});} catch (error) {Logger.error(TAG, `startBackgroundRunning failed. code is ${error.code} message is ${error.message}`);}});}...
}

暂停音乐播放,结束长时任务。

// BackgroundTaskUtil.ets
import wantAgent from '@ohos.app.ability.wantAgent';
import backgroundTaskManager from '@ohos.resourceschedule.backgroundTaskManager';
...
export class BackgroundTaskUtil {...public static stopContinuousTask(context: Context) {if (context === undefined) {Logger.info(TAG, 'stopContinuousTask fail,context is empty.');return;}try {backgroundTaskManager.stopBackgroundRunning(context).then(() => {Logger.info(TAG, 'stopBackgroundRunning succeeded');}).catch((err: Error) => {Logger.error(TAG, 'stopBackgroundRunning failed Cause: ' + JSON.stringify(err));});} catch (error) {Logger.error(TAG, `stopBackgroundRunning failed. code is ${error.code} message is ${error.message}`);}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/643723.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

QML 不同风格和主题的切换

Quick程序提供了方便的用于切换不同风格和主题的配置文件,如果没有设计稿,又想界面没那么丑,那么可以用这套配置,让应用看起来相对专业一点。 一,在 qrc 资源文件中添加 qtquickcontrols2.conf 文件。 二,…

[Algorithm][前缀和][模板 一维前缀和][模板 二维前缀和][寻找数组中心下标][除自身以外数组的乘积] + 前缀和原理 + 前缀和模板

目录 0.原理讲解1.[模板]一维前缀和1.题目链接2.模板代码实现 2.[模板]二维前缀和1.题目链接2.算法原理讲解3.模板代码实现 3.寻找数组的中心下标1.题目链接2.算法原理详解3.代码实现 4.除自身以外数组的乘积1.题目链接2.算法原理详解3.代码实现 0.原理讲解 前缀和:…

(ICML-2021)从自然语言监督中学习可迁移的视觉模型

从自然语言监督中学习可迁移的视觉模型 Title:Learning Transferable Visual Models From Natural Language Supervision paper是OpenAI发表在ICML 21的工作 paper链接 Abstract SOTA计算机视觉系统经过训练可以预测一组固定的预定目标类别。这种受限的监督形式限制…

数新大数据平台迁移解决方案

随着企业的发展和数字化转型的不断深入,企业数据平台建设过去很多年,技术和架构过于落后,原有的大数据平台越来越难以满足业务需求。而在新的技术架构大数据平台的升级过程中,对数据和任务迁移的一致性、完整性有很高的要求&#…

P1106 删数问题

本题为洛谷&#xff1a; #include<iostream> #include<string> using namespace std; int main(){string n;int k;cin>>n>>k;while(k--){for(int i0;i<n.length();i){if(n[i]>n[i1]){n.erase(i,1); break;} }for(int i0;i<n.length()-1&&…

DeepFaceLab小白教程:视频换脸过程

合适那些人阅读&#xff1f; 适合从未使用过DeepFaceLab的群体。 如果你想基于DeepFaceLab完成一次视频换脸的操作&#xff0c;可以看本篇。 下载方式 GitHub https://github.com/iperov/DeepFaceLab 我是用motrix下载。 网盘 https://pan.baidu.com/share/init?surlO4…

百度GL地图实现选点获取经纬度并且地址逆解析

index.html引入 <script src"https://api.map.baidu.com/api?typewebgl&v1.0&ak你的ak"></script>组件使用 <el-input:disabled"[详情].includes(title)"v-model"formData.site"placeholder""><templat…

vue项目启动npm install和npm run serve时出现错误Failed to resolve loader:node-sass

1.常见问题 问题1&#xff1a;当执行npm run serve时&#xff0c;出现Failed to resolve loader: node-sass&#xff0c;You may need to install it 解决方法&#xff1a; npm install node-sass4.14.1问题2&#xff1a;当执行npm run serve时&#xff0c;出现以下错误 Fa…

【学习】软件测试自动化,是未来的趋势还是当前的必需

在当今快速迭代的软件开发周期中&#xff0c;速度和质量成为了企业生存的关键。随着DevOps实践的普及和持续集成/持续部署&#xff08;CI/CD&#xff09;流程的标准化&#xff0c;软件测试自动化已经从未来的趋势转变为当前的必要性。本文将探讨自动化测试的现状、必要性以及其…

Docker基本管理和虚拟化

一、docker的发展历史 https://www.cnblogs.com/rongba/articles/14782624.htmlhttps://www.cnblogs.com/rongba/articles/14782624.html 二、docker的概述 Docker是一个开源的应用容器引擎&#xff0c;基于go语言开发并遵循了apache2.0协议开源。 Docker是在Linux容器里运行…

JAVASE基础语法(异常、常用类)

一、异常 1.1 什么是异常 异常就是指不正常。是指代码在运行过程中可能发生错误&#xff0c;导致程序无法正常运行。 package com.atguigu.exception;public class TestException {public static void main(String[] args) {int[] arr {1,2,3,4,5};System.out.println(&quo…

iOS - 多线程的安全隐患

文章目录 iOS - 多线程的安全隐患1. 卖票案例2. 多线程安全隐患的解决方案2.1 iOS中的线程同步方案2.2 同步方案的使用2.2.1 OSSpinLock2.2.1.1 使用方法&#xff1a;2.2.1.2 案例 2.2.2 os_unfair_lock2.2.2.1 使用方法&#xff1a;2.2.2.2 案例 2.2.3 pthread_mutex2.2.3.1 使…