大家好,关于歌曲播放器网站源码分享很多朋友都还不太明白,不过没关系,因为今天小编就来为大家分享关于音乐播放网站源码的知识点,相信应该可以解决大家的一些困惑和问题,如果碰巧可以解决您的问题,还望关注下本站哦,希望对各位有所帮助!
介绍
本示例主要演示了如何通过迁移数据进行音乐的分布式播放。实现了音乐播放的跨设备迁移,包括:播放哪首歌曲、播放进度、以及播放状态的保持。
效果展示
搭建环境
安装DevEcoStudio,详情请参考DevEcoStudio下载。设置DevEcoStudio开发环境,DevEcoStudio开发环境需要依赖于网络环境,需要连接上网络才能确保工具的正常使用,可以根据如下两种情况来配置开发环境:
如果可以直接访问Internet,只需进行下载HarmonyOSSDK操作。如果网络不能直接访问Internet,需要通过代理服务器才可以访问,请参考配置开发环境。下载源码,导入项目。
代码结构
│config.json播放器主能力Slice\n││\n│└─utils\n│LogUtil.java\t\t播放器管理者\n│PlayerStateListener.java\t播放器页面布局\n││\n│└─media\t\t\t\t\t歌曲媒体资源\nHomey.mp3\nHomey.wav\nTechnology.mp3\nTechnology.wav
实现步骤
1.实现跨设备迁移标准步骤,参见HarmonyOSSample之AbilityInteraction设备迁移
2.实现一个播放器管理者PlayerManager
2.1.定义播放器的状态,包括:播放、暂停、完成、播放中
privatestaticfinalintPLAY_STATE_PLAY=0x0000001;\nprivatestaticfinalintPLAY_STATE_PAUSE=0x0000002;\nprivatestaticfinalintPLAY_STATE_FINISH=0x0000003;\nprivatestaticfinalintPLAY_STATE_PROGRESS=0x0000004;
2.2.实现基本的方法,包括:播放、暂停、切换歌曲、更新播放进度方法
还有一些辅助方法,包括:设置媒体资源、定时更新播放进度、获取播放总时长、要用到Player/Timer/自定义的PlayerStateListener/EventHandler事件处理/PlayCallBack播放器回调类
/**\n*play\n*/\npublicvoidplay(){\ntry{\nif(!isPrepared){\nLogUtil.error(TAG,&34;);\nreturn;\n}\n//如果开始播放则返回真;否则返回false。\nif(!musicPlayer.play()){\nLogUtil.error(TAG,&34;);\nreturn;\n}\nstartTask();\nhandler.sendEvent(PLAY_STATE_PLAY);\n}catch(IllegalArgumentExceptione){\nLogUtil.error(TAG,e.getMessage());\ne.printStackTrace();\n}\n}\n\n/**\n*pause\n*/\npublicvoidpause(){\nif(!musicPlayer.pause()){\nLogUtil.info(TAG,&34;);\nreturn;\n}\n//停止计时\nfinishTask();\n//\nhandler.sendEvent(PLAY_STATE_PAUSE);\n}\n/**\n*switchmusic\n*\n*@paramurimusicuri\n*/\npublicvoidswitchMusic(Stringuri){\ncurrentUri=uri;\n//设置资源\nsetResource(currentUri);\n//播放\nplay();\n}\n\n/**\n*changestheplaybackposition\n*更新当前播放进度\n*\n*@paramcurrentTimecurrenttime\n*/\npublicvoidrewindTo(intcurrentTime){\nmusicPlayer.rewindTo(currentTime*1000);\n}\n\n/**\n*setsource\n*\n*@paramurimusicuri\n*/\npublicvoidsetResource(Stringuri){\nLogUtil.info(TAG,&34;+uri);\ntry{\nRawFileEntryrawFileEntry=context.getResourceManager().getRawFileEntry(uri);\nBaseFileDescriptorbaseFileDescriptor=rawFileEntry.openRawFileDescriptor();\n//LogUtil.info(TAG,&34;+baseFileDescriptor);\nif(!musicPlayer.setSource(baseFileDescriptor)){\nLogUtil.info(TAG,&34;);\nreturn;\n}\n//准备播放环境并缓冲媒体数据。\nisPrepared=musicPlayer.prepare();\nLogUtil.info(TAG,&34;+isPrepared);\n//歌曲名称\nStringlistenerUri=currentUri.substring(currentUri.lastIndexOf(&34;)+1,currentUri.lastIndexOf(&34;));\nplayerStateListener.onUriSet(listenerUri);\nLogUtil.info(TAG,&34;+listenerUri);\n}catch(IOExceptione){\nLogUtil.error(TAG,&34;);\n}\n}\n/**\n*定时事件通知更新进度条\n*/\nprivatevoidstartTask(){\nLogUtil.debug(TAG,&34;);\nfinishTask();\ntimerTask=newTimerTask(){\n@Override\npublicvoidrun(){\nhandler.sendEvent(PLAY_STATE_PROGRESS);\n}\n};\ntimer=newTimer();\ntimer.schedule(timerTask,DELAY_TIME,PERIOD);\n}\n\nprivatevoidfinishTask(){\nLogUtil.debug(TAG,&34;);\nif(timer!=null&&timerTask!=null){\ntimer.cancel();\ntimer=null;\ntimerTask=null;\n}\n}\n\n
2.3.PlayerStateListener播放器状态监听器有如下方法:
onPlaySuccess播放成功时被调用onPauseSuccess暂停时被调用onPositionChange进度发生变化时被调用onMusicFinished音乐播放完成时被调用onUriSet资源被设置时被调用
/**\n*PlayerStateListener\n*/\npublicinterfacePlayerStateListener{\nvoidonPlaySuccess(inttotalTime);\n\nvoidonPauseSuccess();\n\nvoidonPositionChange(intcurrentTime);\n\nvoidonMusicFinished();\n\nvoidonUriSet(Stringname);\n}
2.4.PlayCallBack播放器回调类实现了Player.IPlayerCallback接口,实现了如下方法:
onPrepared当媒体文件准备好播放时调用。onMessage当收到播放器消息或警报时调用。onError收到播放器错误消息时调用。onResolutionChanged当视频大小改变时调用。onPlayBackComplete播放完成时调用。onRewindToComplete当播放位置被Player.rewindTo(long)改变时调用。onBufferingChange当缓冲百分比更新时调用。onNewTimedMetaData当有新的定时元数据可用时调用。onMediaTimeIncontinuity当媒体时间连续性中断时调用,例如播放过程中出现错误,播放位置被Player.rewindTo(long)改变,或者播放速度突然改变。
/**\n*在播放完成、播放位置更改和视频大小更改时提供媒体播放器回调。\n*/\nprivateclassPlayCallBackimplementsPlayer.IPlayerCallback{\n\n/**\n*当媒体文件准备好播放时调用。\n*/\n@Override\npublicvoidonPrepared(){\nLogUtil.info(TAG,&34;);\n}\n\n/**\n*当收到播放器消息或警报时调用。\n*\n*@paramtype\n*@paramextra\n*/\n@Override\npublicvoidonMessage(inttype,intextra){\nLogUtil.info(TAG,&34;+type+&34;+extra);\n}\n\n\n/**\n*收到播放器错误消息时调用。\n*\n*@paramerrorType\n*@paramerrorCode\n*/\n@Override\npublicvoidonError(interrorType,interrorCode){\nLogUtil.info(TAG,&34;+errorType+&34;+errorCode);\n}\n\n/**\n*当视频大小改变时调用。\n*\n*@paramwidth\n*@paramheight\n*/\n@Override\npublicvoidonResolutionChanged(intwidth,intheight){\nLogUtil.info(TAG,&34;+width+&34;+height);\n}\n\n/**\n*播放完成时调用。\n*/\n@Override\npublicvoidonPlayBackComplete(){\n//不会自动被调用????\nLogUtil.info(TAG,&34;);\nhandler.sendEvent(PLAY_STATE_FINISH);\n\n}\n\n/**\n*当播放位置被Player.rewindTo(long)改变时调用。\n*/\n@Override\npublicvoidonRewindToComplete(){\nLogUtil.info(TAG,&34;);\n}\n\n/**\n*当缓冲百分比更新时调用。\n*\n*@parampercent\n*/\n@Override\npublicvoidonBufferingChange(intpercent){\nLogUtil.info(TAG,&34;+percent);\n}\n\n/**\n*当有新的定时元数据可用时调用。\n*\n*@parammediaTimedMetaData\n*/\n@Override\npublicvoidonNewTimedMetaData(Player.MediaTimedMetaDatamediaTimedMetaData){\nLogUtil.info(TAG,&34;);\n}\n\n\n/**\n*当媒体时间连续性中断时调用,例如播放过程中出现错误,播放位置被Player.rewindTo(long)改变,或者播放速度突然改变。\n*\n*@parammediaTimeInfo\n*/\n@Override\npublicvoidonMediaTimeIncontinuity(Player.MediaTimeInfomediaTimeInfo){\nLogUtil.info(TAG,&34;);\n}\n}
3.MainAbilitySlice中implementsPlayerStateListener,IAbilityContinuation接口
publicclassMainAbilitySliceextendsAbilitySliceimplementsPlayerStateListener,IAbilityContinuation{\n…
3.1.实现PlayerStateListener接口方法
@Override\npublicvoidonPlaySuccess(inttotalTime){\nLogUtil.debug(TAG,&34;);\n//设置图标\nmusicPlayButton.setPixelMap(ResourceTable.Media_ic_himusic_pause);\n//设置总时长文本\nthis.totalTimeText.setText(getTime(totalTime));\n//设置进度条\nslider.setMaxValue(totalTime);\n//设置当前歌曲海报\nmusicPosters.setPixelMap(posters[currentPos]);\n}\n\n@Override\npublicvoidonPauseSuccess(){\nLogUtil.debug(TAG,&34;);\n//设置图标\nmusicPlayButton.setPixelMap(ResourceTable.Media_ic_himusic_play);\n}\n\n@Override\npublicvoidonUriSet(Stringname){\nLogUtil.debug(TAG,&34;);\n//设置歌曲名称\nmusicNameText.setText(name);\n}\n\n@Override\npublicvoidonPositionChange(intcurrentTime){\nif(currentTime<totalTime){\nLogUtil.info(TAG,&34;+currentTime+&34;+totalTime);\nthis.currentTime=currentTime;\n//设置播放时间文本\nthis.currentTimeText.setText(getTime(currentTime));\n//设置进度条的当前播放时间\nslider.setProgressValue(currentTime);\n}else{\nLogUtil.info(TAG,&34;);\n\n//设置播放器图标\nmusicPlayButton.setPixelMap(ResourceTable.Media_ic_himusic_play);\n}\n}\n\n/**\n*音乐播放完成时应该被调用,但是没被调用\n*/\n@Override\npublicvoidonMusicFinished(){\n//TODO???????????\nLogUtil.debug(TAG,&34;);\ncurrentPos=currentPos==0?1:0;\ncurrentUri=musics[currentPos];\n//切换歌曲\nplayerManager.switchMusic(currentUri);\n//总时长\ntotalTime=playerManager.getTotalTime();\n}\n\n
3.2.实现IAbilityContinuation接口方法
@Override\npublicbooleanonStartContinuation(){\nLogUtil.debug(TAG,&34;);\nreturntrue;\n}\n\n@Override\npublicbooleanonSaveData(IntentParamsintentParams){\nLogUtil.debug(TAG,&34;);\n//\nintentParams.setParam(KEY_CURRENT_TIME,currentTime);\nintentParams.setParam(KEY_POSITION,currentPos);\nintentParams.setParam(KEY_PLAY_STATE,String.valueOf(playerManager.isPlaying()));\nLogUtil.info(TAG,&34;+currentTime);\nreturntrue;\n}\n\n@Override\npublicbooleanonRestoreData(IntentParamsintentParams){\nLogUtil.debug(TAG,&34;);\nif(!(intentParams.getParam(KEY_POSITION)instanceofInteger)){\nreturnfalse;\n}\nif(!(intentParams.getParam(KEY_CURRENT_TIME)instanceofInteger)){\nreturnfalse;\n}\nif(!(intentParams.getParam(KEY_PLAY_STATE)instanceofString)){\nreturnfalse;\n}\n\n//恢复数据,获取迁移过来的参数:播放位置、时间和播放状态\ncurrentPos=(int)intentParams.getParam(KEY_POSITION);\ncurrentTime=(int)intentParams.getParam(KEY_CURRENT_TIME);\nObjectobject=intentParams.getParam(KEY_PLAY_STATE);\n\n\nif(objectinstanceofString){\nisPlaying=Boolean.parseBoolean((String)object);\n}\nisInteractionPlay=true;\nLogUtil.info(TAG,&34;+currentTime);\nreturntrue;\n}\n\n@Override\npublicvoidonCompleteContinuation(inti){\nterminate();\n}
3.3.定义ValueChangedListenerImpl进度值变化的监听事件
实现Slider.ValueChangedListener接口方法
/**\n*进度条值变化的监听事件\n*/\nprivateclassValueChangedListenerImplimplementsSlider.ValueChangedListener{\n@Override\npublicvoidonProgressUpdated(Sliderslider,intprogress,booleanfromUser){\ncurrentTime=progress;\n}\n\n@Override\npublicvoidonTouchStart(Sliderslider){\nLogUtil.debug(TAG,&34;);\n}\n\n@Override\npublicvoidonTouchEnd(Sliderslider){\nLogUtil.debug(TAG,&34;);\n//快速更改播放进度\nplayerManager.rewindTo(currentTime);\n//当前播放时间\ncurrentTimeText.setText(getTime(currentTime));\n}\n}\n\n
3.4.定义迁移数据的KEY,音乐当前的播放时间、播放的歌曲索引(位置)、播放状态
privatestaticfinalStringKEY_CURRENT_TIME=&34;;\nprivatestaticfinalStringKEY_POSITION=&34;;\nprivatestaticfinalStringKEY_PLAY_STATE=&34;;\nprivateintcurrentPos=0;\nprivateStringcurrentUri;\n//是否是互动播放,true表示远端迁移恢复的\nprivatebooleanisInteractionPlay;\nprivateintcurrentTime;\n//当前播放歌曲总时长\nprivateinttotalTime;\nprivatebooleanisPlaying;
3.5.定义播放的音乐URI,这里准备了2首,还有对应的海报
privatestaticfinalStringURI1=&34;;\nprivatestaticfinalStringURI2=&34;;\nprivatefinalString[]musics={URI1,URI2};\nprivatefinalint[]posters={ResourceTable.Media_album,ResourceTable.Media_album2};
3.6.onStart完成数据的初始化
@Override\npublicvoidonStart(Intentintent){\nsuper.onStart(intent);\nsuper.setUIContent(ResourceTable.Layout_main_ability_slice);\n\ninitComponents();\n\ninitMedia();\n\nupdateUI();\n}
初始化界面组件,实现对应按钮的监听事件
播放或暂停、上一首、下一首、迁移以及进度条的进度变化事件的监听
/**\n*初始化界面组件,实现对应按钮的监听事件\n*播放或暂停、上一首、下一首、迁移以及进度条的进度变化事件的监听\n*/\nprivatevoidinitComponents(){\nLogUtil.debug(TAG,&34;);\nmusicNameText=(Text)findComponentById(ResourceTable.Id_music_name);\ncurrentTimeText=(Text)findComponentById(ResourceTable.Id_play_progress_time);\ntotalTimeText=(Text)findComponentById(ResourceTable.Id_play_total_time);\n\nmusicPosters=(Image)findComponentById(ResourceTable.Id_music_posters);\n\nmusicPlayButton=(Image)findComponentById(ResourceTable.Id_music_play_btn);\nfindComponentById(ResourceTable.Id_remote_play).setClickedListener(this::continueAbility);\nfindComponentById(ResourceTable.Id_music_play_prev_btn).setClickedListener(this::prevMusic);\nfindComponentById(ResourceTable.Id_music_play_next_btn).setClickedListener(this::nextMusic);\n\nmusicPlayButton.setClickedListener(this::playOrPauseMusic);\n\n//\nslider=(Slider)findComponentById(ResourceTable.Id_play_progress_bar);\nslider.setValueChangedListener(newValueChangedListenerImpl());\n}\n\nprivatevoidcontinueAbility(Componentcomponent){\ntry{\ncontinueAbility();\n}catch(IllegalStateExceptione){\nLogUtil.info(TAG,e.getMessage());\n}\n}\n\n/**\n*上一首\n*@paramcomponent\n*/\nprivatevoidprevMusic(Componentcomponent){\ncurrentPos=currentPos==0?1:0;\ncurrentUri=musics[currentPos];\n//\nplayerManager.switchMusic(currentUri);\n//总时长\ntotalTime=playerManager.getTotalTime();\n}\n\n/**\n*下一首\n*@paramcomponent\n*/\nprivatevoidnextMusic(Componentcomponent){\ncurrentPos=currentPos==0?1:0;\ncurrentUri=musics[currentPos];\n//切换音乐\nplayerManager.switchMusic(currentUri);\n//总时长\ntotalTime=playerManager.getTotalTime();\n}\n\n/**\n*播放或暂停音乐\n*@paramcomponent\n*/\nprivatevoidplayOrPauseMusic(Componentcomponent){\n//\nplayOrPause();\n}\n\n/**\n*播放或暂停\n*/\nprivatevoidplayOrPause(){\n\nLogUtil.debug(TAG,&34;+playerManager);\ntry{\n//\nif(playerManager.isPlaying()){\nLogUtil.debug(TAG,&34;);\nplayerManager.pause();\n}else{\n//设置资源\nplayerManager.setResource(currentUri);\n//设置进度\nplayerManager.rewindTo(currentTime);\nplayerManager.play();\nLogUtil.debug(TAG,&34;);\n}\n}catch(Exceptione){\nLogUtil.error(TAG,&34;);\ne.printStackTrace();\n}\n}
3.7.初始化媒体对象
当前播放歌曲资源,播放器管理者
/**\n*初始化媒体对象\n*当前播放歌曲资源\n*播放器管理者\n*/\nprivatevoidinitMedia(){\nLogUtil.debug(TAG,&34;);\n//当前媒体URI\ncurrentUri=musics[currentPos];\nLogUtil.debug(TAG,&34;+currentUri);\n//初始化playerManager\nplayerManager=newPlayerManager(getApplicationContext(),currentUri);\n\n//弱引用对象,不会阻止它们的引用对象被终结、终结和回收。弱引用最常用于实现规范化映射。\nWeakReference<PlayerStateListener>playerStateListener=newWeakReference<>(this);\n//设置状态监听器\nplayerManager.setPlayerStateListener(playerStateListener.get());\n//初始化播放器信息\nplayerManager.init();\nLogUtil.debug(TAG,&34;);\n}
3.8.远端迁移后恢复播放界面
恢复播放器的播放进度、播放状态、海报、当前时间和总时长、slider播放进度
/**\n*远端迁移后恢复的播放,恢复播放器的播放进度\n*更新UI界面\n*/\nprivatevoidupdateUI(){\nLogUtil.debug(TAG,&34;);\n//海报\nmusicPosters.setPixelMap(posters[currentPos]);\n//当前时间和总时长\ncurrentTimeText.setText(getTime(currentTime));\ntotalTimeText.setText(getTime(playerManager.getTotalTime()));\n//播放进度\nslider.setMaxValue(playerManager.getTotalTime());\nslider.setProgressValue(currentTime);\n\n//总时长\ntotalTime=playerManager.getTotalTime();\n\n//远端迁移恢复\nif(isInteractionPlay){\nLogUtil.debug(TAG,&34;+currentTime);\nplayerManager.rewindTo(currentTime);\nif(!isPlaying){\nreturn;\n}\n//播放\nplayerManager.play();\n}\n}
问题总结
1.onMusicFinished音乐播放完成时应该被调用,但是多数没被调用,只是偶尔会调用。
2.优化了源码中应用启动后,点击播放无法播放的问题
3.优化了播放器播放完当前歌曲更新播放图标
4.增加了相关的注释说明
完整代码
——————原创:老王丨鸿蒙hms开发者高级认证持证人!学习更多鸿蒙OS相关开发技术可以关注我的公众号:鸿蒙开发者老王
好了,关于歌曲播放器网站源码分享和音乐播放网站源码的问题到这里结束啦,希望可以解决您的问题哈!
