HarmonyOS Sample 之 DistributedMusicPlayer分布式音乐播放器

开发 前端 分布式 OpenHarmony
本示例主要演示了如何通过迁移数据进行音乐的分布式播放。实现了音乐播放的跨设备迁移,包括:播放哪首歌曲、播放进度、以及播放状态的保持。

[[419218]]

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

DistributedMusicPlayer分布式音乐播放器

介绍

本示例主要演示了如何通过迁移数据进行音乐的分布式播放。实现了音乐播放的跨设备迁移,包括:播放哪首歌曲、播放进度、以及播放状态的保持。

效果展示

搭建环境

安装DevEco Studio,详情请参考DevEco Studio下载

设置DevEco Studio开发环境,DevEco Studio开发环境需要依赖于网络环境,需要连接上网络才能确保工具的正常使用,可以根据如下两种情况来配置开发环境:

如果可以直接访问Internet,只需进行下载HarmonyOS SDK操作

如果网络不能直接访问Internet,需要通过代理服务器才可以访问,请参考配置开发环境

下载源码,导入项目。

代码结构

  1.   config.json #全局配置文件 
  2. │ 
  3. ├─java 
  4. │  └─ohos 
  5. │      └─samples 
  6. │          └─distributedmusicplayer 
  7. │              │  MainAbility.java 
  8. │              │ 
  9. │              ├─slice 
  10. │              │      MainAbilitySlice.java     #播放器主能力Slice 
  11. │              │ 
  12. │              └─utils 
  13. │                      LogUtil.java     #日志工具类 
  14. │                      PlayerManager.java   #播放器管理者 
  15. │                      PlayerStateListener.java #播放器状态监听器 
  16. │ 
  17. └─resources 
  18.     ├─base 
  19.     │  ├─element 
  20.     │  │      string.json 
  21.     │  │ 
  22.     │  ├─graphic 
  23.     │  │      button_bg.xml 
  24.     │  │ 
  25.     │  ├─layout 
  26.     │  │      main_ability_slice.xml        #播放器页面布局 
  27.     │  │ 
  28.     │  └─media                  #海报、按钮图片资源 
  29.     │          album.png 
  30.     │          album2.png 
  31.     │          bg_blurry.png 
  32.     │          icon.png 
  33.     │          ic_himusic_next.png 
  34.     │          ic_himusic_pause.png 
  35.     │          ic_himusic_play.png 
  36.     │          ic_himusic_previous.png 
  37.     │          remote_play_selected.png 
  38.     │ 
  39.     └─rawfile                   #歌曲媒体资源 
  40.             Homey.mp3 
  41.             Homey.wav 
  42.             Technology.mp3 
  43.             Technology.wav 

实现步骤

1.实现跨设备迁移标准步骤,参见HarmonyOS Sample 之 AbilityInteraction设备迁移

2.实现一个播放器管理者PlayerManager

2.1.定义播放器的状态,包括: 播放、暂停、完成、播放中

  1. private static final int PLAY_STATE_PLAY = 0x0000001; 
  2. private static final int PLAY_STATE_PAUSE = 0x0000002; 
  3. private static final int PLAY_STATE_FINISH = 0x0000003; 
  4. private static final int PLAY_STATE_PROGRESS = 0x0000004; 

2.2.实现基本的方法,包括:播放、暂停、切换歌曲、更新播放进度方法

还有一些辅助方法,包括:设置媒体资源、定时更新播放进度、获取播放总时长、

要用到Player/Timer/自定义的PlayerStateListener/EventHandler事件处理/PlayCallBack播放器回调类

  1. /** 
  2.  * play 
  3.  */ 
  4. public void play() { 
  5.     try { 
  6.         if (!isPrepared) { 
  7.             LogUtil.error(TAG, "prepare fail"); 
  8.             return
  9.         } 
  10.         //如果开始播放则返回真; 否则返回 false。 
  11.         if (!musicPlayer.play()) { 
  12.             LogUtil.error(TAG, "play fail"); 
  13.             return
  14.         } 
  15.         startTask(); 
  16.         handler.sendEvent(PLAY_STATE_PLAY); 
  17.     } catch (IllegalArgumentException e) { 
  18.         LogUtil.error(TAG, e.getMessage()); 
  19.         e.printStackTrace(); 
  20.     } 
  21.  
  22. /** 
  23.  * pause 
  24.  */ 
  25. public void pause() { 
  26.     if (!musicPlayer.pause()) { 
  27.         LogUtil.info(TAG, "pause fail"); 
  28.         return
  29.     } 
  30.     //停止计时 
  31.     finishTask(); 
  32.     // 
  33.     handler.sendEvent(PLAY_STATE_PAUSE); 
  34. /** 
  35.  * switch music 
  36.  * 
  37.  * @param uri music uri 
  38.  */ 
  39. public void switchMusic(String uri) { 
  40.     currentUri = uri; 
  41.     //设置资源 
  42.     setResource(currentUri); 
  43.     //播放 
  44.     play(); 
  45.  
  46. /** 
  47.  * changes the playback position 
  48.  * 更新当前播放进度 
  49.  * 
  50.  * @param currentTime current time 
  51.  */ 
  52. public void rewindTo(int currentTime) { 
  53.     musicPlayer.rewindTo(currentTime * 1000); 
  54.  
  55. /** 
  56.  * set source 
  57.  * 
  58.  * @param uri music uri 
  59.  */ 
  60. public void setResource(String uri) { 
  61.     LogUtil.info(TAG, "setResource,uri:  " + uri); 
  62.     try { 
  63.         RawFileEntry rawFileEntry = context.getResourceManager().getRawFileEntry(uri); 
  64.         BaseFileDescriptor baseFileDescriptor = rawFileEntry.openRawFileDescriptor(); 
  65.         //LogUtil.info(TAG, "setResource,baseFileDescriptor :  " + baseFileDescriptor); 
  66.         if (!musicPlayer.setSource(baseFileDescriptor)) { 
  67.             LogUtil.info(TAG, "uri is invalid"); 
  68.             return
  69.         } 
  70.         //准备播放环境并缓冲媒体数据。 
  71.         isPrepared = musicPlayer.prepare(); 
  72.         LogUtil.info(TAG, "setResource,isPrepared:  " + isPrepared); 
  73.         //歌曲名称 
  74.         String listenerUri = currentUri.substring(currentUri.lastIndexOf("/") + 1, currentUri.lastIndexOf(".")); 
  75.         playerStateListener.onUriSet(listenerUri); 
  76.         LogUtil.info(TAG, "setResource,listenerUri:  " + listenerUri); 
  77.     } catch (IOException e) { 
  78.         LogUtil.error(TAG, "io exception"); 
  79.     } 
  80. /** 
  81.  * 定时事件通知更新进度条 
  82.  */ 
  83. private void startTask() { 
  84.     LogUtil.debug(TAG, "startTask"); 
  85.     finishTask(); 
  86.     timerTask = new TimerTask() { 
  87.         @Override 
  88.         public void run() { 
  89.             handler.sendEvent(PLAY_STATE_PROGRESS); 
  90.         } 
  91.     }; 
  92.     timer = new Timer(); 
  93.     timer.schedule(timerTask, DELAY_TIME, PERIOD); 
  94.  
  95. private void finishTask() { 
  96.     LogUtil.debug(TAG, "finishTask"); 
  97.     if (timer != null && timerTask != null) { 
  98.         timer.cancel(); 
  99.         timer = null
  100.         timerTask = null
  101.     } 
  102. }  

2.3.PlayerStateListener播放器状态监听器有如下方法:

onPlaySuccess播放成功时被调用

onPauseSuccess暂停时被调用

onPositionChange进度发生变化时被调用

onMusicFinished音乐播放完成时被调用

onUriSet资源被设置时被调用

  1. /** 
  2.  * PlayerStateListener 
  3.  */ 
  4. public interface PlayerStateListener { 
  5.     void onPlaySuccess(int totalTime); 
  6.  
  7.     void onPauseSuccess(); 
  8.  
  9.     void onPositionChange(int currentTime); 
  10.  
  11.     void onMusicFinished(); 
  12.  
  13.     void onUriSet(String name); 

2.4.PlayCallBack播放器回调类实现了Player.IPlayerCallback接口,实现了如下方法:

onPrepared 当媒体文件准备好播放时调用。

onMessage当收到播放器消息或警报时调用。

onError收到播放器错误消息时调用。

onResolutionChanged当视频大小改变时调用。

onPlayBackComplete播放完成时调用。

onRewindToComplete 当播放位置被 Player.rewindTo(long) 改变时调用。

onBufferingChange当缓冲百分比更新时调用。

onNewTimedMetaData当有新的定时元数据可用时调用。

onMediaTimeIncontinuity当媒体时间连续性中断时调用,例如播放过程中出现错误,播放位置被Player.rewindTo(long)改变,或者播放速度突然改变。

  1. /** 
  2.  * 在播放完成、播放位置更改和视频大小更改时提供媒体播放器回调。 
  3.  */ 
  4. private class PlayCallBack implements Player.IPlayerCallback { 
  5.  
  6.     /** 
  7.      * 当媒体文件准备好播放时调用。 
  8.      */ 
  9.     @Override 
  10.     public void onPrepared() { 
  11.         LogUtil.info(TAG, "onPrepared"); 
  12.     } 
  13.  
  14.     /** 
  15.      * 当收到播放器消息或警报时调用。 
  16.      * 
  17.      * @param type 
  18.      * @param extra 
  19.      */ 
  20.     @Override 
  21.     public void onMessage(int type, int extra) { 
  22.         LogUtil.info(TAG, "onMessage  " + type + "-" + extra); 
  23.     } 
  24.  
  25.  
  26.     /** 
  27.      * 收到播放器错误消息时调用。 
  28.      * 
  29.      * @param errorType 
  30.      * @param errorCode 
  31.      */ 
  32.     @Override 
  33.     public void onError(int errorType, int errorCode) { 
  34.         LogUtil.info(TAG, "onError  " + errorType + "-" + errorCode); 
  35.     } 
  36.  
  37.     /** 
  38.      * 当视频大小改变时调用。 
  39.      * 
  40.      * @param width 
  41.      * @param height 
  42.      */ 
  43.     @Override 
  44.     public void onResolutionChanged(int width, int height) { 
  45.         LogUtil.info(TAG, "onResolutionChanged  " + width + "-" + height); 
  46.     } 
  47.  
  48.     /** 
  49.      * 播放完成时调用。 
  50.      */ 
  51.     @Override 
  52.     public void onPlayBackComplete() { 
  53.         //不会自动被调用???? 
  54.         LogUtil.info(TAG, "onPlayBackComplete----------------"); 
  55.         handler.sendEvent(PLAY_STATE_FINISH); 
  56.  
  57.     } 
  58.  
  59.     /** 
  60.      * 当播放位置被 Player.rewindTo(long) 改变时调用。 
  61.      */ 
  62.     @Override 
  63.     public void onRewindToComplete() { 
  64.         LogUtil.info(TAG, "onRewindToComplete"); 
  65.     } 
  66.  
  67.     /** 
  68.      * 当缓冲百分比更新时调用。 
  69.      * 
  70.      * @param percent 
  71.      */ 
  72.     @Override 
  73.     public void onBufferingChange(int percent) { 
  74.         LogUtil.info(TAG, "onBufferingChange:" + percent); 
  75.     } 
  76.  
  77.     /** 
  78.      * 当有新的定时元数据可用时调用。 
  79.      * 
  80.      * @param mediaTimedMetaData 
  81.      */ 
  82.     @Override 
  83.     public void onNewTimedMetaData(Player.MediaTimedMetaData mediaTimedMetaData) { 
  84.         LogUtil.info(TAG, "onNewTimedMetaData"); 
  85.     } 
  86.  
  87.  
  88.     /** 
  89.      * 当媒体时间连续性中断时调用,例如播放过程中出现错误,播放位置被Player.rewindTo(long)改变,或者播放速度突然改变。 
  90.      * 
  91.      * @param mediaTimeInfo 
  92.      */ 
  93.     @Override 
  94.     public void onMediaTimeIncontinuity(Player.MediaTimeInfo mediaTimeInfo) { 
  95.         LogUtil.info(TAG, "onNewTimedMetaData"); 
  96.     } 

3.MainAbilitySlice 中 implements PlayerStateListener , IAbilityContinuation接口

  1. public class MainAbilitySlice extends AbilitySlice implements PlayerStateListener, IAbilityContinuation { 
  2. ... 

3.1.实现PlayerStateListener接口方法

  1. @Override 
  2. public void onPlaySuccess(int totalTime) { 
  3.     LogUtil.debug(TAG, "onPlaySuccess"); 
  4.     //设置图标 
  5.     musicPlayButton.setPixelMap(ResourceTable.Media_ic_himusic_pause); 
  6.     //设置总时长文本 
  7.     this.totalTimeText.setText(getTime(totalTime)); 
  8.     //设置进度条 
  9.     slider.setMaxValue(totalTime); 
  10.     //设置当前歌曲海报 
  11.     musicPosters.setPixelMap(posters[currentPos]); 
  12.  
  13. @Override 
  14. public void onPauseSuccess() { 
  15.     LogUtil.debug(TAG, "onPauseSuccess"); 
  16.     //设置图标 
  17.     musicPlayButton.setPixelMap(ResourceTable.Media_ic_himusic_play); 
  18.  
  19. @Override 
  20. public void onUriSet(String name) { 
  21.     LogUtil.debug(TAG, "onUriSet"); 
  22.     //设置歌曲名称 
  23.     musicNameText.setText(name); 
  24.  
  25. @Override 
  26. public void onPositionChange(int currentTime) { 
  27.    if(currentTime < totalTime){ 
  28.        LogUtil.info(TAG, "onPositionChange currentTime = " + currentTime+",totalTime="+totalTime); 
  29.        this.currentTime = currentTime; 
  30.         //设置播放时间文本 
  31.         this.currentTimeText.setText(getTime(currentTime)); 
  32.         //设置进度条的当前播放时间 
  33.         slider.setProgressValue(currentTime); 
  34.     }else
  35.        LogUtil.info(TAG, "onPositionChange, current song end"); 
  36.  
  37.        //设置播放器图标 
  38.         musicPlayButton.setPixelMap(ResourceTable.Media_ic_himusic_play); 
  39.     } 
  40.  
  41. /** 
  42.  *音乐播放完成时应该被调用,但是没被调用 
  43.  */ 
  44. @Override 
  45. public void onMusicFinished() { 
  46.     //TODO??????????? 
  47.     LogUtil.debug(TAG, "onMusicFinished"); 
  48.     currentPos = currentPos == 0 ? 1 : 0; 
  49.     currentUri = musics[currentPos]; 
  50.     //切换歌曲 
  51.     playerManager.switchMusic(currentUri); 
  52.     //总时长 
  53.     totalTime=playerManager.getTotalTime(); 

3.2.实现IAbilityContinuation接口方法

  1. @Override 
  2. public boolean onStartContinuation() { 
  3.     LogUtil.debug(TAG, "onStartContinuation"); 
  4.     return true
  5.  
  6. @Override 
  7. public boolean onSaveData(IntentParams intentParams) { 
  8.     LogUtil.debug(TAG, "onSaveData"); 
  9.     // 
  10.     intentParams.setParam(KEY_CURRENT_TIME, currentTime); 
  11.     intentParams.setParam(KEY_POSITION, currentPos); 
  12.     intentParams.setParam(KEY_PLAY_STATE, String.valueOf(playerManager.isPlaying())); 
  13.     LogUtil.info(TAG, "onSaveData:" + currentTime); 
  14.     return true
  15.  
  16. @Override 
  17. public boolean onRestoreData(IntentParams intentParams) { 
  18.     LogUtil.debug(TAG, "onRestoreData"); 
  19.     if (!(intentParams.getParam(KEY_POSITION) instanceof Integer)) { 
  20.         return false
  21.     } 
  22.     if (!(intentParams.getParam(KEY_CURRENT_TIME) instanceof Integer)) { 
  23.         return false
  24.     } 
  25.     if (!(intentParams.getParam(KEY_PLAY_STATE) instanceof String)) { 
  26.         return false
  27.     } 
  28.  
  29.     //恢复数据,获取迁移过来的参数:播放位置、时间和播放状态 
  30.     currentPos = (int) intentParams.getParam(KEY_POSITION); 
  31.     currentTime = (int) intentParams.getParam(KEY_CURRENT_TIME); 
  32.     Object object = intentParams.getParam(KEY_PLAY_STATE); 
  33.  
  34.  
  35.     if (object instanceof String) { 
  36.         isPlaying = Boolean.parseBoolean((String) object); 
  37.     } 
  38.     isInteractionPlay = true
  39.     LogUtil.info(TAG, "onRestoreData:" + currentTime); 
  40.     return true
  41.  
  42. @Override 
  43. public void onCompleteContinuation(int i) { 
  44.     terminate(); 

3.3.定义ValueChangedListenerImpl进度值变化的监听事件

实现 Slider.ValueChangedListener 接口方法

  1. /** 
  2.  *进度条值变化的监听事件 
  3.  */ 
  4. private class ValueChangedListenerImpl implements Slider.ValueChangedListener { 
  5.     @Override 
  6.     public void onProgressUpdated(Slider slider, int progress, boolean fromUser) { 
  7.         currentTime = progress; 
  8.     } 
  9.  
  10.     @Override 
  11.     public void onTouchStart(Slider slider) { 
  12.         LogUtil.debug(TAG, "onTouchStart"); 
  13.     } 
  14.  
  15.     @Override 
  16.     public void onTouchEnd(Slider slider) { 
  17.         LogUtil.debug(TAG, "onTouchEnd"); 
  18.         //快速更改播放进度 
  19.         playerManager.rewindTo(currentTime); 
  20.         //当前播放时间 
  21.         currentTimeText.setText(getTime(currentTime)); 
  22.     } 

3.4.定义迁移数据的KEY,音乐当前的播放时间、播放的歌曲索引(位置)、播放状态

  1. private static final String KEY_CURRENT_TIME = "main_ability_slice_current_time"
  2. private static final String KEY_POSITION = "main_ability_slice_position"
  3. private static final String KEY_PLAY_STATE = "main_ability_slice_play_state"
  4. private int currentPos = 0; 
  5. private String currentUri; 
  6. //是否是互动播放,true表示远端迁移恢复的 
  7. private boolean isInteractionPlay; 
  8. private int currentTime; 
  9. //当前播放歌曲总时长 
  10. private int totalTime; 
  11. private boolean isPlaying; 

 3.5.定义播放的音乐URI,这里准备了2首,还有对应的海报

  1. private static final String URI1 = "resources/rawfile/Technology.wav"
  2. private static final String URI2 = "resources/rawfile/Homey.wav"
  3. private final String[] musics = {URI1, URI2}; 
  4. private final int[] posters = {ResourceTable.Media_album, ResourceTable.Media_album2}; 

 3.6.onStart完成数据的初始化

  1. @Override 
  2. public void onStart(Intent intent) { 
  3.     super.onStart(intent); 
  4.     super.setUIContent(ResourceTable.Layout_main_ability_slice); 
  5.  
  6.     initComponents(); 
  7.  
  8.     initMedia(); 
  9.  
  10.     updateUI(); 

初始化界面组件,实现对应按钮的监听事件

播放或暂停、上一首、下一首、迁移以及进度条的进度变化事件的监听

  1. /** 
  2.  * 初始化界面组件,实现对应按钮的监听事件 
  3.  * 播放或暂停、上一首、下一首、迁移以及进度条的进度变化事件的监听 
  4.  */ 
  5. private void initComponents() { 
  6.     LogUtil.debug(TAG, "initComponents"); 
  7.     musicNameText = (Text) findComponentById(ResourceTable.Id_music_name); 
  8.     currentTimeText = (Text) findComponentById(ResourceTable.Id_play_progress_time); 
  9.     totalTimeText = (Text) findComponentById(ResourceTable.Id_play_total_time); 
  10.  
  11.     musicPosters = (Image) findComponentById(ResourceTable.Id_music_posters); 
  12.  
  13.     musicPlayButton = (Image) findComponentById(ResourceTable.Id_music_play_btn); 
  14.     findComponentById(ResourceTable.Id_remote_play).setClickedListener(this::continueAbility); 
  15.     findComponentById(ResourceTable.Id_music_play_prev_btn).setClickedListener(this::prevMusic); 
  16.     findComponentById(ResourceTable.Id_music_play_next_btn).setClickedListener(this::nextMusic); 
  17.  
  18.     musicPlayButton.setClickedListener(this::playOrPauseMusic); 
  19.  
  20.     // 
  21.     slider = (Slider) findComponentById(ResourceTable.Id_play_progress_bar); 
  22.     slider.setValueChangedListener(new ValueChangedListenerImpl()); 
  23.  
  24. private void continueAbility(Component component) { 
  25.     try { 
  26.         continueAbility(); 
  27.     } catch (IllegalStateException e) { 
  28.         LogUtil.info(TAG, e.getMessage()); 
  29.     } 
  30.  
  31. /** 
  32.  * 上一首 
  33.  * @param component 
  34.  */ 
  35. private void prevMusic(Component component) { 
  36.     currentPos = currentPos == 0 ? 1 : 0; 
  37.     currentUri = musics[currentPos]; 
  38.     // 
  39.     playerManager.switchMusic(currentUri); 
  40.     //总时长 
  41.     totalTime=playerManager.getTotalTime(); 
  42.  
  43. /** 
  44.  * 下一首 
  45.  * @param component 
  46.  */ 
  47. private void nextMusic(Component component) { 
  48.     currentPos = currentPos == 0 ? 1 : 0; 
  49.     currentUri = musics[currentPos]; 
  50.     //切换音乐 
  51.     playerManager.switchMusic(currentUri); 
  52.     //总时长 
  53.     totalTime=playerManager.getTotalTime(); 
  54.  
  55. /** 
  56.  * 播放或暂停音乐 
  57.  * @param component 
  58.  */ 
  59. private void playOrPauseMusic(Component component) { 
  60.     // 
  61.     playOrPause(); 
  62.  
  63. /** 
  64.  * 播放或暂停 
  65.  */ 
  66. private void playOrPause() { 
  67.  
  68.     LogUtil.debug(TAG, "playOrPause,playerManager:"+playerManager); 
  69.     try { 
  70.         // 
  71.         if (playerManager.isPlaying()) { 
  72.             LogUtil.debug(TAG, "playOrPause pause"); 
  73.             playerManager.pause(); 
  74.         }else
  75.             //设置资源 
  76.             playerManager.setResource(currentUri); 
  77.             //设置进度 
  78.             playerManager.rewindTo(currentTime); 
  79.             playerManager.play(); 
  80.             LogUtil.debug(TAG, "playOrPause play"); 
  81.         } 
  82.     } catch (Exception e) { 
  83.         LogUtil.error(TAG, "playOrPause"); 
  84.         e.printStackTrace(); 
  85.     } 

3.7.初始化媒体对象

当前播放歌曲资源,播放器管理者

  1. /** 
  2.  * 初始化媒体对象 
  3.  * 当前播放歌曲资源 
  4.  * 播放器管理者 
  5.  */ 
  6. private void initMedia() { 
  7.     LogUtil.debug(TAG, "initMedia"); 
  8.     //当前媒体URI 
  9.     currentUri = musics[currentPos]; 
  10.     LogUtil.debug(TAG, "initMedia,currentUri:"+currentUri); 
  11.     //初始化playerManager 
  12.     playerManager = new PlayerManager(getApplicationContext(), currentUri); 
  13.  
  14.     //弱引用对象,不会阻止它们的引用对象被终结、终结和回收。 弱引用最常用于实现规范化映射。 
  15.     WeakReference<PlayerStateListener> playerStateListener = new WeakReference<>(this); 
  16.     //设置状态监听器 
  17.     playerManager.setPlayerStateListener(playerStateListener.get()); 
  18.     //初始化播放器信息 
  19.     playerManager.init(); 
  20.     LogUtil.debug(TAG, "initMedia FINISH"); 

3.8.远端迁移后恢复播放界面

恢复播放器的播放进度、播放状态、海报、当前时间和总时长、slider播放进度

  1. /** 
  2.  * 远端迁移后恢复的播放,恢复播放器的播放进度 
  3.  * 更新UI界面 
  4.  */ 
  5. private void updateUI() { 
  6.     LogUtil.debug(TAG, "updateUI"); 
  7.     //海报 
  8.     musicPosters.setPixelMap(posters[currentPos]); 
  9.     //当前时间和总时长 
  10.     currentTimeText.setText(getTime(currentTime)); 
  11.     totalTimeText.setText(getTime(playerManager.getTotalTime())); 
  12.     //播放进度 
  13.     slider.setMaxValue(playerManager.getTotalTime()); 
  14.     slider.setProgressValue(currentTime); 
  15.  
  16.     //总时长 
  17.     totalTime=playerManager.getTotalTime(); 
  18.  
  19.     //远端迁移恢复 
  20.     if (isInteractionPlay) { 
  21.         LogUtil.debug(TAG, "remotePlay,rewindTo:"+currentTime); 
  22.         playerManager.rewindTo(currentTime); 
  23.         if (!isPlaying) { 
  24.             return
  25.         } 
  26.         //播放 
  27.         playerManager.play(); 
  28.     } 

问题总结

1.onMusicFinished 音乐播放完成时应该被调用,但是多数没被调用,只是偶尔会调用,难道是我电脑性能跟不上了?

2.优化了源码中应用启动后,点击播放无法播放的问题

3.优化了播放器播放完当前歌曲更新播放图标

4.增加了相关的注释说明

附件直接下载DistributedMusicPlayer.zip

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

 

责任编辑:jianghua 来源: 鸿蒙社区
相关推荐

2022-11-08 15:48:35

应用开发音乐播放器

2021-12-10 15:06:56

鸿蒙HarmonyOS应用

2021-12-02 10:11:44

鸿蒙HarmonyOS应用

2021-10-21 16:00:07

鸿蒙HarmonyOS应用

2021-10-19 14:27:07

鸿蒙HarmonyOS应用

2011-06-27 11:23:21

Qt 音乐播放器

2014-12-31 16:52:53

音乐播放器源码

2009-12-17 15:10:31

Linux音乐播放器

2021-07-23 08:57:32

鸿蒙HarmonyOS应用

2021-10-21 10:03:09

鸿蒙HarmonyOS应用

2021-11-16 09:38:10

鸿蒙HarmonyOS应用

2021-07-22 10:20:21

鸿蒙HarmonyOS应用

2020-09-29 19:20:05

鸿蒙

2019-02-11 09:20:35

Linux音乐播放器

2017-03-01 14:01:31

android多媒体音乐代码

2017-02-20 09:15:34

Linux播放器Qmmp

2011-04-06 10:03:45

谷歌云计算Android音

2020-11-06 12:12:35

HarmonyOS

2011-08-30 09:48:07

Ubuntu

2018-07-17 08:14:22

分布式分布式锁方位
点赞
收藏

51CTO技术栈公众号