| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239 |
- ---
- description: 音乐播放器开发模式与最佳实践
- globs: ["**/view/**/*.ets", "**/viewmodel/**/*.ets", "**/controller/**/*.ets"]
- alwaysApply: false
- ---
- # 音乐播放器开发模式与最佳实践
- ## 播放状态管理
- ### 播放状态枚举
- 使用 `PlayStatus` 枚举管理播放状态:
- ```typescript
- import { PlayStatus } from '../common/PlayStatus';
- // 在组件中使用
- @State playStatus: PlayStatus = PlayStatus.INIT;
- ```
- ### 状态转换模式
- ```typescript
- // 播放/暂停切换
- togglePlay() {
- if (this.playStatus === PlayStatus.PLAY) {
- this.pauseMusic();
- this.playStatus = PlayStatus.PAUSE;
- } else {
- this.playMusic();
- this.playStatus = PlayStatus.PLAY;
- }
- }
- ```
- ## 音频会话管理
- ### AvSessionController使用
- ```typescript
- import { AvSessionController } from '../controller/AvSessionController';
- // 获取控制器实例
- private avSessionController = AvSessionController.getInstance();
- // 在页面生命周期中注册/注销
- aboutToAppear() {
- this.avSessionController.registerSessionListener();
- }
- aboutToDisappear() {
- this.avSessionController.unregisterSessionListener();
- }
- ```
- ## 歌词处理模式
- ### 歌词解析与显示
- ```typescript
- // 使用lib中的LyricHelper
- import { LyricHelper } from '@lib/LyricHelper';
- // 解析歌词文件
- LyricHelper.parseLyricFile(lyricPath)
- .then(lyrics => {
- this.lyrics = lyrics;
- })
- .catch((err: Error) => {
- Logger.error(`歌词解析失败: ${err.message}`);
- });
- ```
- ### 歌词同步显示
- ```typescript
- // 根据当前播放时间获取对应歌词行
- getCurrentLyricLine(currentTime: number): LyricLine | null {
- if (!this.lyrics || this.lyrics.length === 0) {
- return null;
- }
-
- for (let i = 0; i < this.lyrics.length; i++) {
- if (this.lyrics[i].time > currentTime) {
- return i > 0 ? this.lyrics[i - 1] : null;
- }
- }
-
- return this.lyrics[this.lyrics.length - 1];
- }
- ```
- ## 媒体文件处理
- ### 支持的音频格式
- 使用 `CommonConstants.REAL_MUSIC_FORMAT` 检查文件格式:
- ```typescript
- import { CommonConstants } from '../common/constants/CommonConstants';
- function isMusicFile(fileName: string): boolean {
- const ext = fileName.substring(fileName.lastIndexOf('.')).toLowerCase();
- return CommonConstants.REAL_MUSIC_FORMAT.includes(ext);
- }
- ```
- ### 媒体扫描与索引
- ```typescript
- // 扫描本地音乐文件
- async scanLocalMusic(): Promise<MusicItem[]> {
- const musicFiles: MusicItem[] = [];
- const context = getContext(this);
-
- // 使用文件系统API扫描
- // 实现细节取决于具体需求
-
- return musicFiles;
- }
- ```
- ## 播放列表管理
- ### 播放列表模型
- ```typescript
- import { Playlist } from '../viewmodel/Playlist';
- // 创建播放列表
- const playlist = new Playlist();
- playlist.name = "我的播放列表";
- playlist.songs = [song1, song2, song3];
- // 保存到本地存储
- PreferencesUtil.saveObject('playlist_' + playlist.id, playlist);
- ```
- ### 播放模式
- ```typescript
- // 播放模式枚举
- enum PlayMode {
- SEQUENCE, // 顺序播放
- LOOP, // 循环播放
- RANDOM, // 随机播放
- SINGLE // 单曲循环
- }
- // 切换播放模式
- switchPlayMode() {
- const modes = Object.values(PlayMode);
- const currentIndex = modes.indexOf(this.playMode);
- this.playMode = modes[(currentIndex + 1) % modes.length];
- }
- ```
- ## 主题适配
- ### 主题切换
- ```typescript
- import { myTheme } from '../common/AppTheme';
- // 在组件中使用主题颜色
- @Builder
- PlayerControl() {
- Row() {
- Button('播放')
- .backgroundColor($r('app.color.brand'))
- .fontColor($r('app.color.fontOnPrimary'))
- }
- .backgroundColor($r('app.color.backgroundPrimary'))
- }
- ```
- ### 动态主题更新
- ```typescript
- // 更新主题
- updateTheme(themeIndex: number) {
- const themeList = [DefaultTheme, TwilightTheme, ForestTheme, CoralTheme, MidnightTheme];
- AppStorage.SetOrCreate('themeColor', themeList[themeIndex].colors.brand);
- }
- ```
- ## 性能优化
- ### 图片加载优化
- ```typescript
- // 使用缓存和懒加载
- Image(this.coverUrl)
- .width(50)
- .height(50)
- .borderRadius(8)
- .objectFit(ImageFit.Cover)
- .alt($r('app.media.default_music_icon'))
- .onComplete(() => {
- // 加载完成回调
- })
- .onError(() => {
- // 加载失败回调
- })
- ```
- ### 列表性能优化
- ```typescript
- // 使用LazyForEach和缓存
- LazyForEach(this.musicData, (item: MusicItem, index: number) => {
- ListItem() {
- MusicItemComponent({ musicItem: item })
- }
- }, (item: MusicItem) => item.id.toString())
- ```
- ## 错误处理
- ### 播放错误处理
- ```typescript
- // 播放错误处理
- handlePlaybackError(error: Error) {
- Logger.error(`播放错误: ${error.message}`);
- this.playStatus = PlayStatus.INIT;
-
- // 显示错误提示
- ToastUtil.showToast(`播放失败: ${error.message}`);
- }
- ```
- ### 网络请求错误处理
- ```typescript
- // API请求错误处理
- fetchLyrics(title: string, artist: string) {
- const url = `${CommonConstants.LRC_API}?title=${encodeURIComponent(title)}&artist=${encodeURIComponent(artist)}`;
-
- fetch(url)
- .then(response => {
- if (!response.ok) {
- throw new Error(`HTTP error! status: ${response.status}`);
- }
- return response.json();
- })
- .then(data => {
- this.processLyrics(data);
- })
- .catch((err: Error) => {
- Logger.error(`获取歌词失败: ${err.message}`);
- // 使用备用API或显示错误
- });
- }
- ```
|