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.mzph.cn/web/2482.shtml

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

相关文章

安全小课堂丨什么是暴力破解?如何防止暴力破解

什么是暴力破解? 暴力破解也可称为穷举法、枚举法,是一种比较流行的密码破译方法,也就是将密码进行一一推算直到找出正确的密码为止。比如一个6位并且全部由数字组成的密码,可能有100万种组合,也就是说最多需要尝试10…

JWT原理解析

一、概述 虽然现在很多的开发框架会支持JWT的使用,但是对JWT还是没有一个详细的了解,有很多疑惑: JWT比之前的session或者token有什么好处?JWT的构成元素是什么?JWT从生成到使用的详细流程? 二、 JWT 2…

SPI Flash and External SPI RAM(基于ESP32)

主要参考资料: 乐鑫ESP-IDF资料SPI Flash API: https://docs.espressif.com/projects/esp-idf/zh_CN/v5.1/esp32s3/api-reference/peripherals/spi_flash/index.html 乐鑫ESP-IDF资料SPI Flash and External SPI RAM Configuration: https://docs.espressif.com/pro…

场景 - 分库分表

分什么 数据量大分表,并发大分库 分表字段如何选择 如果对交易订单进行分表,可以选择的东西很多,比如说商户id,用户id,地区等等 分表的时候要考虑到数据倾斜问题 数据倾斜 比如说按商户号进行分表,一共…

pnpm 安装后 node_modules 是什么结构?为什么 webpack 不识别 pnpm 安装的包?

本篇研究:使用 pnpm 安装依赖时,node_modules 下是什么结构 回顾 npm3 之前:依赖树 缺点: frequently packages were creating too deep dependency trees, which caused long directory paths issue on Windowspackages were c…

Day 20 Linux的WEB服务——apache

WEB服务简介 目前主流的web服务器软件 Linux:apache , nginx Windows-server:IIS 服务器安装nginx或apache后,叫做web服务器(又称WWW服务器) web服务器软件属于C/S框架模型 web服务器是一种被动程序只…

薄板样条插值TPS原理以及torch和opencv实现

薄板样条插值TPS原理以及torch和opencv实现 1、薄板样条插值TPS原理概述原理以及公式推导2、torch实现3、opencv实现1、薄板样条插值TPS原理 概述 薄板样条(Thin Plate Spline),简称TPS,是一种插值方法,可找到通过所有给定点的“最小弯曲”光滑曲面。因为它一般都是基于…

UE4网络图片加载库(带内存缓存和磁盘缓存)

UE4网络图片加载库,带内存缓存和磁盘缓存,支持自定义缓存大小,支持蓝图和C++代码调用 1、调用示例 2、对外暴露函数 3、源代码-网络模块 KeImageNet.h // Fill out your copyright notice in the Description page of Project Settings.#pragma once#include "CoreM…

Vue基于高德地图API封装一个地图组件

一、参考资料 高德开放平台 | 高德地图API (amap.com) 二、安装及配置 pnpm i vuemap/vue-amap --save man.ts 密钥及安全密钥需要自己到高德地图开放平台控制台获取. import { createApp } from vue import App from ./App.vue import router from ./router i…

java实现解析html获取图片或视频url

一、前言 有时在实际项目中,比如发布某篇文章,需要取文章中的某张图片作为封面,那么此时需要文章内容,获取html内容中的图片地址作为封面,下面讲下如何获取html中的图片或视频地址。 二、实现 1.先定义一个工具类&…

Python学习教程(Python学习路线+Python学习视频):Python数据结构

数据结构引言: 数据结构是组织数据的方式,以便能够更好的存储和获取数据。数据结构定义数据之间的关系和对这些数据的操作方式。数据结构屏蔽了数据存储和操作的细节,让程序员能更好的处理业务逻辑,同时拥有快速的数据存储和获取方…

android openGL ES详解

1、渲染线程与主线程的通信 两个线程之间的通信可以用如下方法: 在主线程中的 GLSurfaceView 实例可以调用 queueEvent( )方法传递一个 Runnable 给后台渲染线程,渲染线程可以调用 Activity 的 runOnUIThread()来传递事件 (event) 给主线程。 2、顶点…

Redhawk:ATE如何产生top level sta file

我正在「拾陆楼」和朋友们讨论有趣的话题,你⼀起来吧? 拾陆楼知识星球入口 相关文章链接 redhawk: create STA file 在“redhawk: create STA file”一文中介绍了ate的用法,可以应对block level的设计,但当需要做top level分析时&

构建安全高效的前端权限控制系统

✨✨谢谢大家捧场,祝屏幕前的小伙伴们每天都有好运相伴左右,一定要天天开心哦!✨✨ 🎈🎈作者主页: 喔的嘛呀🎈🎈 ✨✨ 帅哥美女们,我们共同加油!一起进步&am…

单片机学习过程

继电器光耦隔离电压转换步进电机直流电机 arduino是最好用的一种,他提供了完整的设备库文件,任何外部设备只要查找相应的库,就可以很方便的使用 , 但是如果不去学习51 或stm32 或 嵌入式玩玩还可以,如果碰到没有实现的…

使用 IPAM 解决方案简化分布式网络管理

随着组织在数字领域的全球扩张,分布式网络是不可避免的,这意味着,随着 IT 基础设施的发展,组织需要适应,这包括在不断增长的系统需求、应用程序堆栈、各种协议和安全防御中监控、现代化和简化流程和资源。在有效管理现…

盲人过马路安全:科技力量赋予“隐形守护者”

作为一名资深记者,我始终关注着社会各群体的生活现状,尤其是那些面临特殊挑战的人群。今天,我想聚焦一个看似平常却对盲人构成重大困扰的日常场景——过马路,以及一款名为蝙蝠避障的辅助应用如何成为他们的盲人过马路安全的守护者…

自制Apache-Doris 2.0.4镜像Docker部署一Fe和一Be集群及遇到的问题解决

自制Apache-Doris 2.0.4镜像Docker部署一Fe和一Be集群及遇到的问题解决 文章目录 1.前言2.doris是什么?2.1简介2.2介绍2.3使用场景2.4架构 3.官网4.构建部署4.1 构建环境4.2 doris2.0.4的fe和be镜像构建4.2.1 fe2.0.4镜像构建脚本4.2.2 be2.0.4镜像构建4.2.3 启动脚…

FebHost:科技企业如何规划并注册.AI域名?

为确保企业使用.AI域名的方式准确反映其对人工智能技术的关注,企业应考虑以下步骤: 了解法律和合规要求: 第一步是了解与 .AI 域名相关的独特法律和合规要求。由于.AI域名源于安圭拉,企业必须遵守安圭拉的限制和法律规定。这包括…

C语言 字符类型

下面 我们来说字符类型 我们来看这个 保险单 金额 和 总额 都可以用数字类型 而性别则需要字符型 字符数据的存储 – ASCI码 字符类型 char 就是专为存储字符(如字母,标点和数字)而设计的类型。 使用单引号包含单个字符或转义字符去表示一个 char 类型的常量。 …