Android毕设音乐播放器实现
基于MediaPlayer技术实现在线音乐播放器,播放在线音乐,后端使用SpringBoot将音乐存放在Tomcat服务器。app通过网络请求获取音乐,从而实现在线音乐播放。该项目分为用户端和管理员端
一、核心技术Service组件介绍
Service它可以在后台执行长时间运行操作而没有用户界面的应用组件,不依赖任何用户界面,例如后台播放音乐,后台下载文件等。
虽然服务是在后台运行的,但是Service和Activity都是运行在当前APP所在的main thread(UI主线程)中的,而耗时操作(如网络请求、拷贝数据、大文件)会阻塞主线程,给用户带来不好的体验。如果需要在服务中进行耗时操作,可以选择 IntentService,IntentService是Service的子类,用来处理异步请求。
二、如何使用SerVice
创建Service直接在Android Studio中右键选择Service创建即可。默认我们所创建的Service是继承Service的。同时我们为了实现后台音乐播放的功能,所以我们还要实MediaPlayer.OnCompletionListener的接口。
同时还要在AndroidManifest.xml文件中对已经创建的Service进行注册,这一点Android Studio已经帮我们自动创建好了
三、Service启动的两种方式
(1)在Acitivity界面通过显式意图(或隐式意图)的方式来启动服务和关闭服务。
Intent intentService =newIntent(MainActivity.this,AudioService.class);startService(intentService);
(2)bindService()绑定服务
当应用组件通过调用 bindService() 绑定到服务时,服务即处于“绑定”状态。绑定服务提供了一个客户端-服务器接口,允许组件与服务进行交互、发送请求、获取结果。 仅当与另一个应用组件绑定时,绑定服务才会运行。 多个组件可以同时绑定到该服务,但全部取消绑定后,该服务即会被销毁。
1. 用户端功能模块:登录,注册,音乐推荐,音乐分类,个人中心,音乐浏览记录,我的下载,上一曲,下一曲,音乐下载
2.管理员模块:登录,注册,用户管理,音乐分类管理(添加分类,删除分类,编辑分类),音乐管理(修改歌名,移动音乐分类,删除音乐)
3.部分核心代码实现
欢迎页
/**
* 欢迎页
*/@SuppressLint("CustomSplashScreen")publicclassSplashActivityextendsBaseActivity<ActivitySplashBinding>{@OverrideprotectedActivitySplashBindinggetViewBinding(){returnActivitySplashBinding.inflate(getLayoutInflater());}@OverrideprotectedvoidsetListener(){}@OverrideprotectedvoidinitData(){newHandler(Looper.myLooper()).postDelayed(newRunnable(){@Overridepublicvoidrun(){startActivity(newIntent(mContext,LoginActivity.class));finish();}},800);}}
用户主页面
/**
* 用户主页面
*/publicclassMainActivityextendsBaseActivity<ActivityMainBinding>{privateString[] titles ={"音乐推荐","音乐分类"};privateList<Fragment> fragmentList =newArrayList<>();@OverrideprotectedActivityMainBindinggetViewBinding(){returnActivityMainBinding.inflate(getLayoutInflater());}@OverrideprotectedvoidsetListener(){
mBinding.avatar.setOnClickListener(newView.OnClickListener(){@OverridepublicvoidonClick(View view){startActivityForResult(newIntent(MainActivity.this,MineActivity.class),20002);}});}@OverrideprotectedvoidinitData(){if(ApiConstants.getUserInfo()!=null){
mBinding.username.setText(ApiConstants.getUserInfo().getUsername());}//造数据
fragmentList.add(newHomeFragment());
fragmentList.add(newTypeFragment());// fragmentList.add(new RecordFragment());//如果处理成懒加载的话,其实很简单,只要是这个方法setOffscreenPageLimit不去设置,就可以了。// mBinding.viewPager.setOffscreenPageLimit(fragmentList.size());
mBinding.viewPager.setUserInputEnabled(false);
mBinding.viewPager.setAdapter(newFragmentStateAdapter(this){@NonNull@OverridepublicFragmentcreateFragment(int position){return fragmentList.get(position);}@OverridepublicintgetItemCount(){return fragmentList.size();}});
mBinding.tabs.addOnTabSelectedListener(newTabLayout.OnTabSelectedListener(){@OverridepublicvoidonTabSelected(TabLayout.Tab tab){
mBinding.viewPager.setCurrentItem(tab.getPosition(),false);}@OverridepublicvoidonTabUnselected(TabLayout.Tab tab){}@OverridepublicvoidonTabReselected(TabLayout.Tab tab){}});TabLayoutMediator tabLayoutMediator =newTabLayoutMediator(mBinding.tabs, mBinding.viewPager,newTabLayoutMediator.TabConfigurationStrategy(){@OverridepublicvoidonConfigureTab(@NonNullTabLayout.Tab tab,int position){
tab.setText(titles[position]);}});//这句话很重要
tabLayoutMediator.attach();}@OverrideprotectedvoidonActivityResult(int requestCode,int resultCode,@NullableIntent data){super.onActivityResult(requestCode, resultCode, data);if(resultCode ==20002){finish();}}}
音乐播放界面
/**
* 音乐播放界面
*/publicclassPlayMusicActivityextendsBaseActivity<ActivityPlayMusicBinding>implementsOnPlayerEventListener{privatestaticfinalStringTAG="============";privateMusicInfo musicInfo;privateint mLastProgress;@OverrideprotectedActivityPlayMusicBindinggetViewBinding(){returnActivityPlayMusicBinding.inflate(getLayoutInflater());}@OverrideprotectedvoidsetListener(){Aria.download(this).register();
mBinding.sbProgress.setOnSeekBarChangeListener(newSeekBar.OnSeekBarChangeListener(){@OverridepublicvoidonProgressChanged(SeekBar seekBar,int progress,boolean b){if(Math.abs(progress - mLastProgress)>=DateUtils.SECOND_IN_MILLIS){
mBinding.tvCurrentTime.setText(formatTime("mm:ss", progress));
mLastProgress = progress;}}@OverridepublicvoidonStartTrackingTouch(SeekBar seekBar){}@OverridepublicvoidonStopTrackingTouch(SeekBar seekBar){if(AudioPlayer.get().isPlaying()||AudioPlayer.get().isPausing()){int progress = seekBar.getProgress();AudioPlayer.get().seekTo(progress);}else{
seekBar.setProgress(0);}}});
mBinding.ivMusicPlay.setOnClickListener(newView.OnClickListener(){@OverridepublicvoidonClick(View view){AudioPlayer.get().playPause();}});
mBinding.ivMusicPrevious.setOnClickListener(newView.OnClickListener(){@OverridepublicvoidonClick(View view){AudioPlayer.get().prev();}});
mBinding.ivMusicNext.setOnClickListener(newView.OnClickListener(){@OverridepublicvoidonClick(View view){AudioPlayer.get().next();}});//下载
mBinding.download.setOnClickListener(newView.OnClickListener(){@OverridepublicvoidonClick(View view){if(XXPermissions.isGranted(mContext,Permission.Group.STORAGE)){download();}else{checkPermission();}}});}@OverrideprotectedvoidinitData(){initSystemBar();
musicInfo =(MusicInfo)getIntent().getSerializableExtra("musicInfo");//监听AudioPlayer.get().addOnPlayEventListener(this);if(null!= musicInfo){AudioPlayer.get().addAndPlay(musicInfo);//添加到浏览记录addRecord(musicInfo);//获取单个任务实体DownloadEntity entity =Aria.download(this).getFirstDownloadEntity(musicInfo.getMusic_url());if(null!= entity){
mBinding.download.setClickable(false);
mBinding.download.setImageResource(R.mipmap.ic_download_complete);}else{
mBinding.download.setClickable(true);
mBinding.download.setImageResource(R.mipmap.iv_download);}}}/**
* 沉浸式状态栏
*/privatevoidinitSystemBar(){ImmersionBar.with(this).init();}publicStringformatTime(String pattern,long milli){int m =(int)(milli /DateUtils.MINUTE_IN_MILLIS);int s =(int)((milli /DateUtils.SECOND_IN_MILLIS)%60);String mm =String.format(Locale.getDefault(),"%02d", m);String ss =String.format(Locale.getDefault(),"%02d", s);return pattern.replace("mm", mm).replace("ss", ss);}@SuppressLint("SetTextI18n")privatevoidonChangeImpl(MusicInfo music){if(music ==null){return;}
mBinding.sbProgress.setProgress((int)AudioPlayer.get().getAudioPosition());
mBinding.sbProgress.setSecondaryProgress(0);
mLastProgress =0;
mBinding.tvCurrentTime.setText("00:00");if(AudioPlayer.get().isPlaying()||AudioPlayer.get().isPreparing()){
mBinding.ivMusicPlay.setSelected(true);}else{
mBinding.ivMusicPlay.setSelected(false);}
mBinding.toolbar.setTitle(music.getMusic_title());
mBinding.tvMusicTitle.setText(music.getMusic_title());
mBinding.tvMusicSongType.setText(music.getMusic_type());startAnim();}@OverridepublicvoidonChange(MusicInfo music){onChangeImpl(music);}@OverridepublicvoidonPlayerStart(long duration){//一定要设置最大值
mBinding.sbProgress.setMax((int) duration);
mBinding.tvTotalTime.setText(formatTime("mm:ss", duration));
mBinding.ivMusicPlay.setSelected(true);startAnim();}@OverridepublicvoidonPlayerPause(){
mBinding.ivMusicPlay.setSelected(false);stopAnim();}@OverridepublicvoidonPublish(int progress){
mBinding.sbProgress.setProgress(progress);}@OverridepublicvoidonBufferingUpdate(int percent){
mBinding.sbProgress.setSecondaryProgress(mBinding.sbProgress.getMax()*100/ percent);}privateAnimation animation;privatevoidstartAnim(){
animation =AnimationUtils.loadAnimation(this,R.anim.rotation_animation);LinearInterpolator lin =newLinearInterpolator();//设置动画匀速运动
animation.setInterpolator(lin);
mBinding.imgCd.startAnimation(animation);}privatevoidstopAnim(){if(mBinding.imgCd.getAnimation()!=null){
mBinding.imgCd.clearAnimation();}}privatevoidaddRecord(MusicInfo musicInfo){OkGo.<String>get(ApiConstants.ADD_RECORD_MUSIC_URL).params("username",ApiConstants.getUserInfo().getUsername()).params("music_title", musicInfo.getMusic_title()).params("music_url", musicInfo.getMusic_url()).params("music_type", musicInfo.getMusic_type()).execute(newHttpStringCallback(null){@OverrideprotectedvoidonSuccess(String msg,String response){}@OverrideprotectedvoidonError(String response){}});}privatevoidcheckPermission(){XXPermissions.with(this)// 申请单个权限// 申请多个权限.permission(Permission.Group.STORAGE)// 设置权限请求拦截器(局部设置)//.interceptor(new PermissionInterceptor())// 设置不触发错误检测机制(局部设置)//.unchecked().request(newOnPermissionCallback(){@OverridepublicvoidonGranted(List<String> permissions,boolean all){if(!all){showToast("获取部分权限成功,但部分权限未正常授予");return;}//这里做操作}@OverridepublicvoidonDenied(List<String> permissions,boolean never){if(never){showToast("被永久拒绝授权,请手动授予录音和日历权限");// 如果是被永久拒绝就跳转到应用权限系统设置页面XXPermissions.startPermissionActivity(mContext, permissions);}else{showToast("获取录音和日历权限失败");}}});}@Download.onWaitpublicvoidonWait(DownloadTask task){Log.d(TAG,"onWait: ");}@Download.onPrepublicvoidonPre(DownloadTask task){Log.d(TAG,"onPre: ");}@Download.onTaskStartpublicvoidonTaskStart(DownloadTask task){Log.d(TAG,"onTaskStart: ");showToast("开始下载~~~~~");}@Download.onTaskRunningpublicvoidonTaskRunning(DownloadTask task){Log.d(TAG,"onTaskRunning: ");}@Download.onTaskResumepublicvoidonTaskResume(DownloadTask task){Log.d(TAG,"onTaskResume: ");}@Download.onTaskStoppublicvoidonTaskStop(DownloadTask task){Log.d(TAG,"onTaskStop: ");}@Download.onTaskCancelpublicvoidonTaskCancel(DownloadTask task){Log.d(TAG,"onTaskCancel: ");}@Download.onTaskFailpublicvoidonTaskFail(DownloadTask task,Exception e){Log.d(TAG,"onTaskFail: ");}@Download.onTaskCompletepublicvoidonTaskComplete(DownloadTask task){Log.d(TAG,"onTaskComplete: ");
mBinding.download.setClickable(false);
mBinding.download.setImageResource(R.mipmap.ic_download_complete);showToast("下载完成~~~~~");}privatevoiddownload(){if(null!= musicInfo){Aria.download(PlayMusicActivity.this).load(musicInfo.getMusic_url())// 下载地址.setFilePath(getExternalCacheDir().getPath()+ musicInfo.getMusic_title()+".mp3")// 设置文件保存路径.setExtendField(GsonUtils.toJson(musicInfo)).create();}}}
详情可私信哦~~~~~~
版权归原作者 东晋谨慎的冬瓜 所有, 如有侵权,请联系我们删除。