分布式音乐播放器适配了Stage模型

2024-05-24 02:44

本文主要是介绍分布式音乐播放器适配了Stage模型,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

OpenAtom OpenHarmony(以下简称“OpenHarmony”)应用开发自API 8及其更早版本一直使用的是FA模型进行开发。FA模型是Feature Ability的缩写,它和PA(Particle Ability)两种类型是过往长期推广的术语,深入人心。

然而从API 9开始,Ability框架引入了Stage模型作为第二种应用框架形态,Stage模型将Ability分为PageAbility和ExtensionAbility两大类,其中ExtensionAbility又被扩展为ServiceExtensionAbility、FormExtensionAbility、DataShareExtensionAbility等一系列ExtensionAbility,以便满足更多的使用场景。新模型接口中有AbilityStage/WindowStage的概念,这个Stage本身有舞台的意思,寓意是给开发者一个新的展现舞台。Stage模型的设计,主要是为了开发者更加方便地开发出分布式环境下的复杂应用。下表给出了两种模型在设计上的差异:

可以看得出来,新的模型设计的主要目标是把UI与Ability分离,即从架构设计层面,规范开发者编写业务逻辑和UI交互的开发方式。通过数据把UI和业务逻辑解耦,开发者在Ability中产生数据,数据传递给UI框架后,利用ArkTS声明式框架的特点,UI=F(state),通过数据驱动UI变化。这样的设计是为了更好地支持Ability实现跨端迁移和多端协同,即数据都是存储在Ability里,继而通过数据驱动UI展示。此外,FA模型每个Ability使用一个VM实例,而Stage模型整个进程只使用一个VM实例,减少进程内存占用,应用内状态在进程内共享。

分布式音乐播放器,是今年上半年我基于OpenHarmony 3.1,参考OpenHarmony JS分布式音乐播放的Sample代码,使用ArkTS新写的样例,当时的主要目的就是为了学习ArkTS开发页面。此次适配Stage模型后,在润和大禹系列HH-SCDAYU200开发套件上,效果如下图所示:

可以看到,此次更新,不仅使用了Stage模型适配,还使用ArkTS增加了一个音乐播放器首页列表的界面,以及播放时使用属性动画,实现了一个播放音乐时“唱片旋转”的动画效果。这次使用Stage模型适配样例,主要是修改了如下几个地方:

修改点1:代码目录的调整

可以看到,相对于FA的目录结构,首先是在最上层目录里,增加了一个AppScope目录,这个目录下也是resources下的资源文件,比如string.json,图片等内容。这个目录里的资源文件,会在编译时拼接到具体的hap内编译,因此可以把不同hap包里的公用资源提取到这个目录下。

此外是增加了AbilityStage.ts这个文件,它是Hap及加载入口,开发者可以基于它派生完成hap的初始化以及指定多个实例开发。AbilityStage可以配合ApplicationContext监听/管理进程内组件的生命周期,感觉是有点充当了FA模型里的app.ets的作用。

其它的文件也有小的变化,如配置文件,pages位置等都有调整。所以建议还是新建一个stage模型的工程,然后把之前的代码逐步复制过来,然后修改问题。

修改点2:获取设备列表,分布式拉起等API变化

由于两种模型的应用上下文不同,导致一些跟上下文相关的API大都有些变化,在SDK及文档中有明确标明哪些API是stage模型专用的。比如耳熟能详的startAbility分布式拉起应用,在FA模型中是通过以下代码实现:

import featureAbility from '@ohos.ability.featureAbility';featureAbility.startAbility({want: wantValue}).then((data) => {CommonLog.info('startAbilityContinuation finished, ' + JSON.stringify(data))//拉起后,自我关闭featureAbility.terminateSelf((error) => {CommonLog.info('startAbilityContinuation terminateSelf finished, error=' + JSON.stringify(error))})}).catch((error) => {CommonLog.info('startAbilityContinuation error ' + JSON.stringify(error))})

而在stage模型里,由于不再有featureAbility,因此无法import featureAbility,进而无法使用featureAbility.startAbility拉起应用,进而使用getContext获取上下文后,调用startAbility拉起应用。

getContext(this).startAbility(want).then((data) => {CommonLog.info('startAbilityContinuation finished, ' + JSON.stringify(data))//自我关闭getContext(this).terminateSelf((error) => {CommonLog.info('startAbilityContinuation terminateSelf finished, error=' + JSON.stringify(error))})
}).catch((error) => {CommonLog.info('startAbilityContinuation error ' + JSON.stringify(error))
})

除了startAbility外,样例里使用到的获取包含bundleName,设备发现deviceManager的相关API都需要按照上述方法进行修改。

修改点3:数据从组件分离,提取到Ability中

在分布式拉起时,需要传递当前播放的音乐和音乐的播放进度。在两种模型里,这些参数都是被设置在wantValue的parameters里,通过startAbility传出去。

let params = {index: this.playerManager.getCurrentMusicIndex(),seekTo: this.playerManager.getCurrentTimeMs(),isPlaying: this.isPlaying}let wantValue = {bundleName: this.bundleName,abilityName: 'com.madixin.music.MainAbility',deviceId: remoteDevice.deviceId,parameters: params}

但在接收参数时,FA模型里,是在当前组件的代码里,通过featureAbility.getWant来获取参数,如下代码。

featureAbility.getWant((error, want) => {CommonLog.info('restoreFromWant featureAbility.getWant=' + JSON.stringify(want))let status = want.parametersif (status != null && status.index != null) {this.playerManager.playSpecifyMusic(status.seekTo, status.index)this.isPlaying = truethis.playAnimation()}})

而使用Stage模型后,虽然参数传递的方式是一致的,但是无法直接在组件UI中获取参数,而需要先在MainAbility.ts获取参数want。此时如果要传递给组件,有多种方式,这里我是使用的如下方式,即在MainAbility.ts的onCreate和onNewWant里,把want赋值到globalThis里,然后在UI组件里,通过globalThis获取参数。

// MainAbility.ts
onNewWant(want, launchParams) {globalThis.newWant = wanthilog.info(0x0000, 'MyOpenHarmonyPlayer', '%{public}s', 'onNewWant launchParam:' + JSON.stringify(launchParams) ?? '');
}onCreate(want, launchParam) {globalThis.newWant = wanthilog.info(0x0000, 'MyOpenHarmonyPlayer', '%{public}s', 'want param:' + JSON.stringify(want) ?? '');hilog.info(0x0000, 'MyOpenHarmonyPlayer', '%{public}s', 'launchParam:' + JSON.stringify(launchParam) ?? '');
}// index.ets
let newWant = globalThis.newWant
CommonLog.info("aboutToAppear newWant:" + JSON.stringify(newWant))
if (newWant !== null && newWant.parameters.hasOwnProperty("seekTo")) {this.playerManager.playSpecifyMusic(newWant.parameters.seekTo, newWant.parameters.index)
}

另外,了解到还有一种方式传递数据是使用AppStorage来关联,比如在MainAbility.ts里使用AppStorage.SetOrCreate传入数据,在UI组件里,使用@StorageLink标签修饰变量来获取数据。

除以上三点修改外,还有两点值得说明下

首先是因OpenHarmony 3.2后分布式能力限制智能系统应用使用,需要提升apl等级:找到所使用API版本对应toolchains>版本号>lib>UnsgnedReleasedProfileTemplate.json,更改 “apl”: "normal"为 “apl”: “system_core”。

其次是API 9以后区分了public-SDK和Full SDK。DevEco Studio默认下载的是public-SDK,它不包含系统应用所需要的高权限API。当我们import deviceManager from '@ohos.distributedHardware.deviceManager’时,会发现里面只有一个空的接口,没有任何方法。虽然这不影响功能,但代码中必须使用@ts-ignore忽略typescript的告警,而且没有语法提示。此时,需要使用full-SDK替换。

新增首页页面,和播放列表页的动画,不是本文的重点,大家可以参考代码自行学习。

总结

OpenHarmony的FA模型能力已经停止演进,后续将会增强Stage模型。此次将现有的样例代码适配Stage模型,虽然整体代码修改量不大,但因为惯性思维以及API的变化,期间还是踩了不少坑。我已在OpenHarmony知识体系仓中更新了样例代码,欢迎开发者来参考和指正问题,建议新上手OpenHarmony的开发者可以直接学习使用新的Stage模型来开发应用。前面提到在Stage模型里,ExtensionAbility又被扩展为ServiceExtensionAbility、FormExtensionAbility、DataShareExtensionAbility等一系列ExtensionAbility,这个样例目前还没有涉及到,待后续进一步学习,通过ExtensionAbility把音乐播放实现成一个后台服务,从而实现应用在后台时也能继续播放音乐,届时将持续更新这个应用,也欢迎大家一起共建。

为了帮助到大家能够更有效的学习OpenHarmony 开发的内容,下面特别准备了一些相关的参考学习资料:

OpenHarmony 开发环境搭建:https://qr18.cn/CgxrRy

《OpenHarmony源码解析》:https://qr18.cn/CgxrRy

  • 搭建开发环境
  • Windows 开发环境的搭建
  • Ubuntu 开发环境搭建
  • Linux 与 Windows 之间的文件共享
  • ……

系统架构分析:https://qr18.cn/CgxrRy

  • 构建子系统
  • 启动流程
  • 子系统
  • 分布式任务调度子系统
  • 分布式通信子系统
  • 驱动子系统
  • ……

OpenHarmony 设备开发学习手册:https://qr18.cn/CgxrRy

在这里插入图片描述

OpenHarmony面试题(内含参考答案):https://qr18.cn/CgxrRy

这篇关于分布式音乐播放器适配了Stage模型的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/997151

相关文章

Golang的CSP模型简介(最新推荐)

《Golang的CSP模型简介(最新推荐)》Golang采用了CSP(CommunicatingSequentialProcesses,通信顺序进程)并发模型,通过goroutine和channe... 目录前言一、介绍1. 什么是 CSP 模型2. Goroutine3. Channel4. Channe

java如何分布式锁实现和选型

《java如何分布式锁实现和选型》文章介绍了分布式锁的重要性以及在分布式系统中常见的问题和需求,它详细阐述了如何使用分布式锁来确保数据的一致性和系统的高可用性,文章还提供了基于数据库、Redis和Zo... 目录引言:分布式锁的重要性与分布式系统中的常见问题和需求分布式锁的重要性分布式系统中常见的问题和需求

Golang使用etcd构建分布式锁的示例分享

《Golang使用etcd构建分布式锁的示例分享》在本教程中,我们将学习如何使用Go和etcd构建分布式锁系统,分布式锁系统对于管理对分布式系统中共享资源的并发访问至关重要,它有助于维护一致性,防止竞... 目录引言环境准备新建Go项目实现加锁和解锁功能测试分布式锁重构实现失败重试总结引言我们将使用Go作

Redis分布式锁使用及说明

《Redis分布式锁使用及说明》本文总结了Redis和Zookeeper在高可用性和高一致性场景下的应用,并详细介绍了Redis的分布式锁实现方式,包括使用Lua脚本和续期机制,最后,提到了RedLo... 目录Redis分布式锁加锁方式怎么会解错锁?举个小案例吧解锁方式续期总结Redis分布式锁如果追求

Python基于火山引擎豆包大模型搭建QQ机器人详细教程(2024年最新)

《Python基于火山引擎豆包大模型搭建QQ机器人详细教程(2024年最新)》:本文主要介绍Python基于火山引擎豆包大模型搭建QQ机器人详细的相关资料,包括开通模型、配置APIKEY鉴权和SD... 目录豆包大模型概述开通模型付费安装 SDK 环境配置 API KEY 鉴权Ark 模型接口Prompt

鸿蒙开发搭建flutter适配的开发环境

《鸿蒙开发搭建flutter适配的开发环境》文章详细介绍了在Windows系统上如何创建和运行鸿蒙Flutter项目,包括使用flutterdoctor检测环境、创建项目、编译HAP包以及在真机上运... 目录环境搭建创建运行项目打包项目总结环境搭建1.安装 DevEco Studio NEXT IDE

大模型研发全揭秘:客服工单数据标注的完整攻略

在人工智能(AI)领域,数据标注是模型训练过程中至关重要的一步。无论你是新手还是有经验的从业者,掌握数据标注的技术细节和常见问题的解决方案都能为你的AI项目增添不少价值。在电信运营商的客服系统中,工单数据是客户问题和解决方案的重要记录。通过对这些工单数据进行有效标注,不仅能够帮助提升客服自动化系统的智能化水平,还能优化客户服务流程,提高客户满意度。本文将详细介绍如何在电信运营商客服工单的背景下进行

Andrej Karpathy最新采访:认知核心模型10亿参数就够了,AI会打破教育不公的僵局

夕小瑶科技说 原创  作者 | 海野 AI圈子的红人,AI大神Andrej Karpathy,曾是OpenAI联合创始人之一,特斯拉AI总监。上一次的动态是官宣创办一家名为 Eureka Labs 的人工智能+教育公司 ,宣布将长期致力于AI原生教育。 近日,Andrej Karpathy接受了No Priors(投资博客)的采访,与硅谷知名投资人 Sara Guo 和 Elad G

Retrieval-based-Voice-Conversion-WebUI模型构建指南

一、模型介绍 Retrieval-based-Voice-Conversion-WebUI(简称 RVC)模型是一个基于 VITS(Variational Inference with adversarial learning for end-to-end Text-to-Speech)的简单易用的语音转换框架。 具有以下特点 简单易用:RVC 模型通过简单易用的网页界面,使得用户无需深入了

透彻!驯服大型语言模型(LLMs)的五种方法,及具体方法选择思路

引言 随着时间的发展,大型语言模型不再停留在演示阶段而是逐步面向生产系统的应用,随着人们期望的不断增加,目标也发生了巨大的变化。在短短的几个月的时间里,人们对大模型的认识已经从对其zero-shot能力感到惊讶,转变为考虑改进模型质量、提高模型可用性。 「大语言模型(LLMs)其实就是利用高容量的模型架构(例如Transformer)对海量的、多种多样的数据分布进行建模得到,它包含了大量的先验