一、前言
在本教程中,我们将使用 鸿蒙系统(HarmonyOS) 实现一个简朴的音乐播放器应用。该播放器支持基本功能,如播放、停息、上一首、下一首,具有精良的用户界面,风格模仿网易云音乐。
二、功能特点
- 播放功能:实现播放、停息、上一首、下一首切换。
- 播放进度:显示当前播放时间及总时长,并支持进度条拖动。
- 音量调节:通过滑块控制播放音量。
- UI 优化:采用简洁风格布局,用户体验友爱。
三、开发环境
- 开发工具:DevEco Studio
- 鸿蒙版本:API Version 8+
- 设备要求:鸿蒙模拟器或鸿蒙支持设备
四、具体步调
步调 1:添加依赖
在 build.gradle 文件中,添加媒体和布局依赖:
- dependencies {
- implementation fileTree(dir: 'libs', include: ['*.jar', '*.so'])
- implementation 'ohos.media:media:1.0.0'
- implementation 'ohos.agp:agp:1.0.0'
- }
复制代码 同时,配置 config.json 文件,声明所需权限:
- "permissions": [
- "ohos.permission.MEDIA_LOCATION",
- "ohos.permission.READ_MEDIA"
- ]
复制代码 步调 2:完备代码
2.1 主活动文件:MainAbility.java
主活动控制界面显示和用户交互逻辑。
- package com.example.musicplayer;
- import ohos.aafwk.ability.Ability;
- import ohos.aafwk.content.Intent;
- import ohos.agp.components.Slider;
- import ohos.agp.components.Text;
- import ohos.agp.components.Button;
- public class MainAbility extends Ability {
- private PlayerController playerController;
- private PlaylistManager playlistManager;
- @Override
- public void onStart(Intent intent) {
- super.onStart(intent);
- setUIContent(ResourceTable.Layout_ability_main);
- playlistManager = new PlaylistManager();
- playerController = new PlayerController(this, playlistManager);
- setupUI();
- }
- private void setupUI() {
- // 界面组件绑定
- Text trackName = (Text) findComponentById(ResourceTable.Id_track_name);
- Text currentTime = (Text) findComponentById(ResourceTable.Id_current_time);
- Text totalTime = (Text) findComponentById(ResourceTable.Id_total_time);
- Button playButton = (Button) findComponentById(ResourceTable.Id_button_play);
- Button nextButton = (Button) findComponentById(ResourceTable.Id_button_next);
- Button prevButton = (Button) findComponentById(ResourceTable.Id_button_previous);
- Slider volumeSlider = (Slider) findComponentById(ResourceTable.Id_volume_slider);
- Slider progressSlider = (Slider) findComponentById(ResourceTable.Id_progress_slider);
- // 绑定事件
- playButton.setClickedListener(component -> playerController.togglePlayPause());
- nextButton.setClickedListener(component -> playerController.playNextTrack());
- prevButton.setClickedListener(component -> playerController.playPreviousTrack());
- // 更新播放进度和时间
- playerController.setTrackChangeListener((name, duration) -> {
- trackName.setText(name);
- totalTime.setText(formatTime(duration));
- });
- playerController.setTimeUpdateListener((current, duration) -> {
- currentTime.setText(formatTime(current));
- progressSlider.setProgress((int) (current * 100 / duration));
- });
- // 音量控制
- volumeSlider.setValueChangedListener((slider, value, fromUser) -> {
- if (fromUser) playerController.setVolume(value / 100.0f);
- });
- // 播放进度控制
- progressSlider.setValueChangedListener((slider, value, fromUser) -> {
- if (fromUser) playerController.seekTo(value / 100.0f);
- });
- }
- private String formatTime(long timeInMs) {
- int minutes = (int) (timeInMs / 60000);
- int seconds = (int) ((timeInMs % 60000) / 1000);
- return String.format("%02d:%02d", minutes, seconds);
- }
- }
复制代码 2.2 播放器控制:PlayerController.java
播放器控制逻辑包括播放、停息、音量和进度控制。
- package com.example.musicplayer;
- import ohos.app.Context;
- import ohos.media.audio.AudioPlayer;
- import java.util.Timer;
- import java.util.TimerTask;
- public class PlayerController {
- private final AudioPlayer audioPlayer;
- private final PlaylistManager playlistManager;
- private final Timer timer;
- private TimeUpdateListener timeUpdateListener;
- private TrackChangeListener trackChangeListener;
- public PlayerController(Context context, PlaylistManager playlistManager) {
- this.audioPlayer = new AudioPlayer(context);
- this.playlistManager = playlistManager;
- this.timer = new Timer();
- setupPlayer();
- startUpdatingTime();
- }
- private void setupPlayer() {
- audioPlayer.setPlayerStateChangedListener((player, state) -> {
- if (state == AudioPlayer.PlayerState.PLAYING) {
- notifyTrackChange();
- }
- });
- }
- public void playNextTrack() {
- playlistManager.nextTrack();
- playCurrentTrack();
- }
- public void playPreviousTrack() {
- playlistManager.previousTrack();
- playCurrentTrack();
- }
- public void togglePlayPause() {
- if (audioPlayer.isPlaying()) {
- audioPlayer.pause();
- } else {
- playCurrentTrack();
- }
- }
- private void playCurrentTrack() {
- audioPlayer.setSource(playlistManager.getCurrentTrack());
- audioPlayer.prepare();
- }
- public void setVolume(float volume) {
- audioPlayer.setVolume(volume);
- }
- public void seekTo(float progress) {
- long position = (long) (audioPlayer.getDuration() * progress);
- audioPlayer.seekTo(position);
- }
- private void startUpdatingTime() {
- timer.scheduleAtFixedRate(new TimerTask() {
- @Override
- public void run() {
- if (timeUpdateListener != null && audioPlayer.isPlaying()) {
- timeUpdateListener.onTimeUpdate(audioPlayer.getCurrentPosition(), audioPlayer.getDuration());
- }
- }
- }, 0, 1000);
- }
- public void setTimeUpdateListener(TimeUpdateListener listener) {
- this.timeUpdateListener = listener;
- }
- public void setTrackChangeListener(TrackChangeListener listener) {
- this.trackChangeListener = listener;
- }
- private void notifyTrackChange() {
- if (trackChangeListener != null) {
- trackChangeListener.onTrackChange(playlistManager.getCurrentTrackName(), audioPlayer.getDuration());
- }
- }
- public interface TimeUpdateListener {
- void onTimeUpdate(long currentTime, long totalTime);
- }
- public interface TrackChangeListener {
- void onTrackChange(String trackName, long duration);
- }
- }
复制代码 2.3 播放器列表:PlaylistManager.java
- package com.example.musicplayer;
- import java.util.ArrayList;
- import java.util.List;
- public class PlaylistManager {
- private final List<String> playlist;
- private int currentIndex;
- public PlaylistManager() {
- this.playlist = new ArrayList<>();
- loadPlaylist();
- }
- private void loadPlaylist() {
- playlist.add("/data/accounts/account_0/appdata/com.example.musicplayer/res/raw/song1.mp3");
- playlist.add("/data/accounts/account_0/appdata/com.example.musicplayer/res/raw/song2.mp3");
- playlist.add("/data/accounts/account_0/appdata/com.example.musicplayer/res/raw/song3.mp3");
- }
- public String getCurrentTrack() {
- return playlist.get(currentIndex);
- }
- public String getCurrentTrackName() {
- return "歌曲:" + playlist.get(currentIndex).substring(playlist.get(currentIndex).lastIndexOf("/") + 1);
- }
- public void nextTrack() {
- currentIndex = (currentIndex + 1) % playlist.size();
- }
- public void previousTrack() {
- currentIndex = (currentIndex - 1 + playlist.size()) % playlist.size();
- }
- }
复制代码 2.4 布局文件:ability_main.xml
- <?xml version="1.0" encoding="utf-8"?>
- <DirectionalLayout
- xmlns:ohos="http://schemas.huawei.com/res/ohos"
- ohos:width="match_parent"
- ohos:height="match_parent"
- ohos:orientation="vertical">
- <Text
- ohos:id="$+id:track_name"
- ohos:width="match_parent"
- ohos:height="match_content"
- ohos:text="当前无音乐播放"
- ohos:text_size="18fp"
- ohos:margin="16vp"
- ohos:text_alignment="center"/>
- <Text
- ohos:id="$+id:current_time"
- ohos:width="match_content"
- ohos:height="match_content"
- ohos:text="00:00"
- ohos:margin="8vp"/>
- <Slider
- ohos:id="$+id:progress_slider"
- ohos:width="match_parent"
- ohos:height="50vp"/>
- <Text
- ohos:id="$+id:total_time"
- ohos:width="match_content"
- ohos:height="match_content"
- ohos:text="00:00"
- ohos:margin="8vp"/>
- <DirectionalLayout
- ohos:width="match_parent"
- ohos:height="match_content"
- ohos:orientation="horizontal"
- ohos:alignment="center">
- <Button
- ohos:id="$+id:button_previous"
- ohos:width="100vp"
- ohos:height="50vp"
- ohos:text="上一首"/>
- <Button
- ohos:id="$+id:button_play"
- ohos:width="100vp"
- ohos:height="50vp"
- ohos:text="播放/暂停"/>
- <Button
- ohos:id="$+id:button_next"
- ohos:width="100vp"
- ohos:height="50vp"
- ohos:text="下一首"/>
- </DirectionalLayout>
- <Slider
- ohos:id="$+id:volume_slider"
- ohos:width="match_parent"
- ohos:height="50vp"
- ohos:progress="50"/>
- </DirectionalLayout>
复制代码 五、运行效果
在完成代码编写后,运行此鸿蒙音乐播放器应用,可以实现以下效果:
- 主界面展示:
- 显示当前播放的歌曲名称、播放时间(当前时间与总时间)。
- 显示进度条,可以根据歌曲进度实时更新,支持拖动调整进度。
- 显示音量滑块,控制音量巨细。
- 基本控制功能:
- 点击播放/停息按钮时,播放器会停息或继续播放。
- 点击上一首或下一首按钮时,播放器会切换到上一首或下一首歌曲。
- 音量通过滑块调整,调整后的音量实时生效。
- 音频播放控制:
- 播放器能够正常读取 .mp3 文件并进行播放。
- 播放进度和时间显示精确,支持拖动进度条控制播放进度。
界面截图示例
主界面:
- 中部有歌曲名和歌手名称
- 下方有播放、停息、上一首、下一首按钮,音量滑块位于界面底部。
歌词界面:
- 顶部展示歌曲名和歌手信息。
- 中部展示歌曲歌词。
- 下方有播放、停息、上一首、下一首按钮,音量滑块位于界面底部。
六、常见报错及办理方案
在开发和运行过程中,大概会遇到以下一些常见问题:
1. 找不到音频文件
错误信息:FileNotFoundException: Could not find the file ...
办理方案:确保音频文件已经正确放入项目的 resources/raw 目录中,并且文件路径在代码中正确配置。
- 比方,查抄 playlistManager.addTrack 中路径是否正确设置:
- playlist.add("/data/accounts/account_0/appdata/com.example.musicplayer/res/raw/song1.mp3");
复制代码 2. 权限问题
错误信息:Permission denied 或无法访问媒体文件。
办理方案:确保已经在 config.json 文件中声明白相关权限,如:
- "permissions": [
- "ohos.permission.MEDIA_LOCATION",
- "ohos.permission.READ_MEDIA"
- ]
复制代码 如果音频文件未能读取或访问,确认模拟器或设备是否已授予这些权限。
3. UI 显示非常
错误信息:UI 布局未能正确显示或相应。
办理方案:确保 ability_main.xml 中的布局组件已正确配置,并且界面组件的 ID 匹配代码中的 findComponentById 方法。
- 确保每个组件的 width 和 height 设置正确,避免出现元素重叠或不显示的情况。
4. 播放器未相应播放操作
错误信息:点击播放按钮无反应。
办理方案:查抄 audioPlayer.setSource 和 audioPlayer.prepare() 是否成功调用,并确保播放器资源路径正确。
- 调试时可以打印日志,确认播放器是否成功加载并开始播放。
- audioPlayer.setSource(playlistManager.getCurrentTrack());
- audioPlayer.prepare();
- Log.info("Player", "Track prepared: " + playlistManager.getCurrentTrack());
复制代码
5. 内存走漏或资源未释放
错误信息:步调运行时间过长时,大概出现内存占用过高。
办理方案:确保 AudioPlayer 在不需要时被正确释放。可以在活动销毁时调用 audioPlayer.release()。
- @Override
- protected void onStop() {
- super.onStop();
- audioPlayer.release();
- }
复制代码 七、总结
在本教程中,我们使用鸿蒙系统(HarmonyOS)开发了一个简朴的音乐播放器,涵盖了基本的音频播放功能,如播放、停息、上一首、下一首、音量控制、播放进度等功能。通过学习和实现这些功能,能够资助开发者认识鸿蒙系统的 音频播放、UI 计划 和 事件相应 机制。
主要学习点:
- 鸿蒙音频播放 API:通过 AudioPlayer 实现音频的加载、播放、停息和进度控制。
- UI 计划与相应:通过 Button、Slider 等组件计划了播放器的用户界面,并相应用户交互。
- 事件驱动编程:通过事件监听和回调机制实现动态更新界面状态,如播放进度、音量控制等。
未来改进:
- 支持更多格式的音频文件:现在我们只支持 .mp3 格式,未来可以添加对 .wav、.flac 等格式的支持。
- 实现播放列表功能:现在播放器只能播放单曲,未来可以添加播放列表功能,支持用户选择差别的歌曲进行播放。
- 增强用户体验:可以进一步优化 UI 计划,比方添加动画效果、歌曲封面显示等,提拔整体用户体验。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |