【中工开发者】基于鸿蒙系统开发简朴音乐播放器

打印 上一主题 下一主题

主题 1704|帖子 1704|积分 5112

一、前言

在本教程中,我们将使用 鸿蒙系统(HarmonyOS) 实现一个简朴的音乐播放器应用。该播放器支持基本功能,如播放、停息、上一首、下一首,具有精良的用户界面,风格模仿网易云音乐。

二、功能特点


  • 播放功能:实现播放、停息、上一首、下一首切换。
  • 播放进度:显示当前播放时间及总时长,并支持进度条拖动。
  • 音量调节:通过滑块控制播放音量。
  • UI 优化:采用简洁风格布局,用户体验友爱。

三、开发环境



  • 开发工具:DevEco Studio
  • 鸿蒙版本:API Version 8+
  • 设备要求:鸿蒙模拟器或鸿蒙支持设备

四、具体步调

步调 1:添加依赖

在 build.gradle 文件中,添加媒体和布局依赖:
  1. dependencies {
  2.     implementation fileTree(dir: 'libs', include: ['*.jar', '*.so'])
  3.     implementation 'ohos.media:media:1.0.0'
  4.     implementation 'ohos.agp:agp:1.0.0'
  5. }
复制代码
同时,配置 config.json 文件,声明所需权限:
  1. "permissions": [
  2.     "ohos.permission.MEDIA_LOCATION",
  3.     "ohos.permission.READ_MEDIA"
  4. ]
复制代码
步调 2:完备代码

2.1 主活动文件:MainAbility.java

主活动控制界面显示和用户交互逻辑。
  1. package com.example.musicplayer;
  2. import ohos.aafwk.ability.Ability;
  3. import ohos.aafwk.content.Intent;
  4. import ohos.agp.components.Slider;
  5. import ohos.agp.components.Text;
  6. import ohos.agp.components.Button;
  7. public class MainAbility extends Ability {
  8.     private PlayerController playerController;
  9.     private PlaylistManager playlistManager;
  10.     @Override
  11.     public void onStart(Intent intent) {
  12.         super.onStart(intent);
  13.         setUIContent(ResourceTable.Layout_ability_main);
  14.         playlistManager = new PlaylistManager();
  15.         playerController = new PlayerController(this, playlistManager);
  16.         setupUI();
  17.     }
  18.     private void setupUI() {
  19.         // 界面组件绑定
  20.         Text trackName = (Text) findComponentById(ResourceTable.Id_track_name);
  21.         Text currentTime = (Text) findComponentById(ResourceTable.Id_current_time);
  22.         Text totalTime = (Text) findComponentById(ResourceTable.Id_total_time);
  23.         Button playButton = (Button) findComponentById(ResourceTable.Id_button_play);
  24.         Button nextButton = (Button) findComponentById(ResourceTable.Id_button_next);
  25.         Button prevButton = (Button) findComponentById(ResourceTable.Id_button_previous);
  26.         Slider volumeSlider = (Slider) findComponentById(ResourceTable.Id_volume_slider);
  27.         Slider progressSlider = (Slider) findComponentById(ResourceTable.Id_progress_slider);
  28.         // 绑定事件
  29.         playButton.setClickedListener(component -> playerController.togglePlayPause());
  30.         nextButton.setClickedListener(component -> playerController.playNextTrack());
  31.         prevButton.setClickedListener(component -> playerController.playPreviousTrack());
  32.         // 更新播放进度和时间
  33.         playerController.setTrackChangeListener((name, duration) -> {
  34.             trackName.setText(name);
  35.             totalTime.setText(formatTime(duration));
  36.         });
  37.         playerController.setTimeUpdateListener((current, duration) -> {
  38.             currentTime.setText(formatTime(current));
  39.             progressSlider.setProgress((int) (current * 100 / duration));
  40.         });
  41.         // 音量控制
  42.         volumeSlider.setValueChangedListener((slider, value, fromUser) -> {
  43.             if (fromUser) playerController.setVolume(value / 100.0f);
  44.         });
  45.         // 播放进度控制
  46.         progressSlider.setValueChangedListener((slider, value, fromUser) -> {
  47.             if (fromUser) playerController.seekTo(value / 100.0f);
  48.         });
  49.     }
  50.     private String formatTime(long timeInMs) {
  51.         int minutes = (int) (timeInMs / 60000);
  52.         int seconds = (int) ((timeInMs % 60000) / 1000);
  53.         return String.format("%02d:%02d", minutes, seconds);
  54.     }
  55. }
复制代码
2.2 播放器控制:PlayerController.java

播放器控制逻辑包括播放、停息、音量和进度控制。
  1. package com.example.musicplayer;
  2. import ohos.app.Context;
  3. import ohos.media.audio.AudioPlayer;
  4. import java.util.Timer;
  5. import java.util.TimerTask;
  6. public class PlayerController {
  7.     private final AudioPlayer audioPlayer;
  8.     private final PlaylistManager playlistManager;
  9.     private final Timer timer;
  10.     private TimeUpdateListener timeUpdateListener;
  11.     private TrackChangeListener trackChangeListener;
  12.     public PlayerController(Context context, PlaylistManager playlistManager) {
  13.         this.audioPlayer = new AudioPlayer(context);
  14.         this.playlistManager = playlistManager;
  15.         this.timer = new Timer();
  16.         setupPlayer();
  17.         startUpdatingTime();
  18.     }
  19.     private void setupPlayer() {
  20.         audioPlayer.setPlayerStateChangedListener((player, state) -> {
  21.             if (state == AudioPlayer.PlayerState.PLAYING) {
  22.                 notifyTrackChange();
  23.             }
  24.         });
  25.     }
  26.     public void playNextTrack() {
  27.         playlistManager.nextTrack();
  28.         playCurrentTrack();
  29.     }
  30.     public void playPreviousTrack() {
  31.         playlistManager.previousTrack();
  32.         playCurrentTrack();
  33.     }
  34.     public void togglePlayPause() {
  35.         if (audioPlayer.isPlaying()) {
  36.             audioPlayer.pause();
  37.         } else {
  38.             playCurrentTrack();
  39.         }
  40.     }
  41.     private void playCurrentTrack() {
  42.         audioPlayer.setSource(playlistManager.getCurrentTrack());
  43.         audioPlayer.prepare();
  44.     }
  45.     public void setVolume(float volume) {
  46.         audioPlayer.setVolume(volume);
  47.     }
  48.     public void seekTo(float progress) {
  49.         long position = (long) (audioPlayer.getDuration() * progress);
  50.         audioPlayer.seekTo(position);
  51.     }
  52.     private void startUpdatingTime() {
  53.         timer.scheduleAtFixedRate(new TimerTask() {
  54.             @Override
  55.             public void run() {
  56.                 if (timeUpdateListener != null && audioPlayer.isPlaying()) {
  57.                     timeUpdateListener.onTimeUpdate(audioPlayer.getCurrentPosition(), audioPlayer.getDuration());
  58.                 }
  59.             }
  60.         }, 0, 1000);
  61.     }
  62.     public void setTimeUpdateListener(TimeUpdateListener listener) {
  63.         this.timeUpdateListener = listener;
  64.     }
  65.     public void setTrackChangeListener(TrackChangeListener listener) {
  66.         this.trackChangeListener = listener;
  67.     }
  68.     private void notifyTrackChange() {
  69.         if (trackChangeListener != null) {
  70.             trackChangeListener.onTrackChange(playlistManager.getCurrentTrackName(), audioPlayer.getDuration());
  71.         }
  72.     }
  73.     public interface TimeUpdateListener {
  74.         void onTimeUpdate(long currentTime, long totalTime);
  75.     }
  76.     public interface TrackChangeListener {
  77.         void onTrackChange(String trackName, long duration);
  78.     }
  79. }
复制代码
2.3 播放器列表:PlaylistManager.java

  1. package com.example.musicplayer;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. public class PlaylistManager {
  5.     private final List<String> playlist;
  6.     private int currentIndex;
  7.     public PlaylistManager() {
  8.         this.playlist = new ArrayList<>();
  9.         loadPlaylist();
  10.     }
  11.     private void loadPlaylist() {
  12.         playlist.add("/data/accounts/account_0/appdata/com.example.musicplayer/res/raw/song1.mp3");
  13.         playlist.add("/data/accounts/account_0/appdata/com.example.musicplayer/res/raw/song2.mp3");
  14.         playlist.add("/data/accounts/account_0/appdata/com.example.musicplayer/res/raw/song3.mp3");
  15.     }
  16.     public String getCurrentTrack() {
  17.         return playlist.get(currentIndex);
  18.     }
  19.     public String getCurrentTrackName() {
  20.         return "歌曲:" + playlist.get(currentIndex).substring(playlist.get(currentIndex).lastIndexOf("/") + 1);
  21.     }
  22.     public void nextTrack() {
  23.         currentIndex = (currentIndex + 1) % playlist.size();
  24.     }
  25.     public void previousTrack() {
  26.         currentIndex = (currentIndex - 1 + playlist.size()) % playlist.size();
  27.     }
  28. }
复制代码
2.4 布局文件:ability_main.xml

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <DirectionalLayout
  3.     xmlns:ohos="http://schemas.huawei.com/res/ohos"
  4.     ohos:width="match_parent"
  5.     ohos:height="match_parent"
  6.     ohos:orientation="vertical">
  7.     <Text
  8.         ohos:id="$+id:track_name"
  9.         ohos:width="match_parent"
  10.         ohos:height="match_content"
  11.         ohos:text="当前无音乐播放"
  12.         ohos:text_size="18fp"
  13.         ohos:margin="16vp"
  14.         ohos:text_alignment="center"/>
  15.     <Text
  16.         ohos:id="$+id:current_time"
  17.         ohos:width="match_content"
  18.         ohos:height="match_content"
  19.         ohos:text="00:00"
  20.         ohos:margin="8vp"/>
  21.     <Slider
  22.         ohos:id="$+id:progress_slider"
  23.         ohos:width="match_parent"
  24.         ohos:height="50vp"/>
  25.     <Text
  26.         ohos:id="$+id:total_time"
  27.         ohos:width="match_content"
  28.         ohos:height="match_content"
  29.         ohos:text="00:00"
  30.         ohos:margin="8vp"/>
  31.     <DirectionalLayout
  32.         ohos:width="match_parent"
  33.         ohos:height="match_content"
  34.         ohos:orientation="horizontal"
  35.         ohos:alignment="center">
  36.         <Button
  37.             ohos:id="$+id:button_previous"
  38.             ohos:width="100vp"
  39.             ohos:height="50vp"
  40.             ohos:text="上一首"/>
  41.         <Button
  42.             ohos:id="$+id:button_play"
  43.             ohos:width="100vp"
  44.             ohos:height="50vp"
  45.             ohos:text="播放/暂停"/>
  46.         <Button
  47.             ohos:id="$+id:button_next"
  48.             ohos:width="100vp"
  49.             ohos:height="50vp"
  50.             ohos:text="下一首"/>
  51.     </DirectionalLayout>
  52.     <Slider
  53.         ohos:id="$+id:volume_slider"
  54.         ohos:width="match_parent"
  55.         ohos:height="50vp"
  56.         ohos:progress="50"/>
  57. </DirectionalLayout>
复制代码
五、运行效果

在完成代码编写后,运行此鸿蒙音乐播放器应用,可以实现以下效果:

  • 主界面展示

    • 显示当前播放的歌曲名称、播放时间(当前时间与总时间)。
    • 显示进度条,可以根据歌曲进度实时更新,支持拖动调整进度。
    • 显示音量滑块,控制音量巨细。

  • 基本控制功能

    • 点击播放/停息按钮时,播放器会停息或继续播放。
    • 点击上一首或下一首按钮时,播放器会切换到上一首或下一首歌曲。
    • 音量通过滑块调整,调整后的音量实时生效。

  • 音频播放控制

    • 播放器能够正常读取 .mp3 文件并进行播放。
    • 播放进度和时间显示精确,支持拖动进度条控制播放进度。

界面截图示例

   主界面
  

  • 中部有歌曲名和歌手名称
  • 下方有播放、停息、上一首、下一首按钮,音量滑块位于界面底部。
  

  歌词界面
  

  • 顶部展示歌曲名和歌手信息。
  • 中部展示歌曲歌词。
  • 下方有播放、停息、上一首、下一首按钮,音量滑块位于界面底部。
  

  
六、常见报错及办理方案

在开发和运行过程中,大概会遇到以下一些常见问题:
1. 找不到音频文件

错误信息:FileNotFoundException: Could not find the file ...
办理方案:确保音频文件已经正确放入项目的 resources/raw 目录中,并且文件路径在代码中正确配置。


  • 比方,查抄 playlistManager.addTrack 中路径是否正确设置:
    1. playlist.add("/data/accounts/account_0/appdata/com.example.musicplayer/res/raw/song1.mp3");
    复制代码
2. 权限问题

错误信息:Permission denied 或无法访问媒体文件。
办理方案:确保已经在 config.json 文件中声明白相关权限,如:
  1. "permissions": [
  2.     "ohos.permission.MEDIA_LOCATION",
  3.     "ohos.permission.READ_MEDIA"
  4. ]
复制代码
如果音频文件未能读取或访问,确认模拟器或设备是否已授予这些权限。
3. UI 显示非常

错误信息:UI 布局未能正确显示或相应。
办理方案:确保 ability_main.xml 中的布局组件已正确配置,并且界面组件的 ID 匹配代码中的 findComponentById 方法。


  • 确保每个组件的 width 和 height 设置正确,避免出现元素重叠或不显示的情况。
4. 播放器未相应播放操作

错误信息:点击播放按钮无反应。
办理方案:查抄 audioPlayer.setSource 和 audioPlayer.prepare() 是否成功调用,并确保播放器资源路径正确。


  • 调试时可以打印日志,确认播放器是否成功加载并开始播放。
    1. audioPlayer.setSource(playlistManager.getCurrentTrack());
    2. audioPlayer.prepare();
    3. Log.info("Player", "Track prepared: " + playlistManager.getCurrentTrack());
    复制代码

5. 内存走漏或资源未释放

错误信息:步调运行时间过长时,大概出现内存占用过高。
办理方案:确保 AudioPlayer 在不需要时被正确释放。可以在活动销毁时调用 audioPlayer.release()。
  1. @Override
  2. protected void onStop() {
  3.     super.onStop();
  4.     audioPlayer.release();
  5. }
复制代码

七、总结

在本教程中,我们使用鸿蒙系统(HarmonyOS)开发了一个简朴的音乐播放器,涵盖了基本的音频播放功能,如播放、停息、上一首、下一首、音量控制、播放进度等功能。通过学习和实现这些功能,能够资助开发者认识鸿蒙系统的 音频播放UI 计划事件相应 机制。
主要学习点:


  • 鸿蒙音频播放 API:通过 AudioPlayer 实现音频的加载、播放、停息和进度控制。
  • UI 计划与相应:通过 Button、Slider 等组件计划了播放器的用户界面,并相应用户交互。
  • 事件驱动编程:通过事件监听和回调机制实现动态更新界面状态,如播放进度、音量控制等。
未来改进:


  • 支持更多格式的音频文件:现在我们只支持 .mp3 格式,未来可以添加对 .wav、.flac 等格式的支持。
  • 实现播放列表功能:现在播放器只能播放单曲,未来可以添加播放列表功能,支持用户选择差别的歌曲进行播放。
  • 增强用户体验:可以进一步优化 UI 计划,比方添加动画效果、歌曲封面显示等,提拔整体用户体验。


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

涛声依旧在

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表