【Android-Service】基于MVP的音乐播放器demo实现思路(附源码)
最近在学习service相关的内容,在该部分的学习过程中,根据学习视频中的内容进行了总结归纳,以下是音乐播放器demo的开发思路,具体步骤及源码:
有关MVP框架的内容可看: link.
实现效果:
实现思路:
- 新建布局,初始化控件,设置点击事件
- 新建两个接口,一个用来定义相关操作(控制逻辑层),一个用来控制UI
- 创建service,注册service,(此处采用混合开启service的方式)(混合开启service: link.)开启service,绑定service
- 利用service绑定返回的binder对象来实现逻辑层的接口,UI接口
- 利用presenter实现逻辑操作,将该实例化对象给service
- 播放音频时的逻辑处理
- 将音频设置到模拟机上,manifest中设置读取权限
- 编写音频播放时、停止时的内部逻辑,修改button的显示内容
- 编写播放、暂停、停止时进度条的内部逻辑
- 实现进度条UI更新
——————————————————————————————
实现源码:
manifest中设置读写权限:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
音频文件存放路径:
IPlayerViewControl.java
public interface IPlayerViewControl {void onPlayStateChange(int state); //播放状态改变的通知,state为当前状态void onSeekChange(int seek); //播放进度改变
}
IPlayerControl.java
public interface IPlayControl {//播放状态public static final int PLAY_STATE_PLAY=1; //播放public static final int PLAY_STATE_PAUSE=2; //暂停public static final int PLAY_STATE_STOP=3; //停止void regiestViewController(IPlayerViewControl viewController); //把UI的控制接口设置给逻辑层void unRegiestViewController(); //取消接口通知的注册void playOrPause(); //播放或暂停音乐void stop(); //停止播放void seekTo(int seek); //设置播放进度,seek表示播放进度
}
PlayerPresenter
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Binder;
import android.util.Log;import com.example.serviceddemo.interfaces.IPlayControl;
import com.example.serviceddemo.interfaces.IPlayerViewControl;import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;public class PlayerPresenter extends Binder implements IPlayControl {private static final String TAG ="PlayerPresenter" ;private IPlayerViewControl mViewController; //这个变量用来控制UIprivate int currentState=PLAY_STATE_STOP; //默认状态为暂停private MediaPlayer mediaPlayer;private Timer timer;private SeekTimeTask seekTimeTask;@Overridepublic void regiestViewController(IPlayerViewControl viewController) {this.mViewController=viewController;}@Overridepublic void unRegiestViewController() {mViewController=null;}@Overridepublic void playOrPause() {Log.d(TAG,"playOrPause......");if(currentState == PLAY_STATE_STOP){//暂停状态,此时是没有播放器的,创建播放器initPlayer();//如果不为空的话就设置数据源if(mediaPlayer != null){try {mediaPlayer.setDataSource("/mnt/sdcard/song.mp3");mediaPlayer.prepare();mediaPlayer.start();currentState=PLAY_STATE_PLAY;startTimer();} catch (IOException e) {e.printStackTrace();}}}else if(currentState == PLAY_STATE_PLAY){ //如果当前的状态是播放的,那就去暂停if (mediaPlayer != null){mediaPlayer.pause();currentState=PLAY_STATE_PAUSE;stopTimer();}}else if (currentState == PLAY_STATE_PAUSE){ //如果当前的状态是暂停的,就继续播放音乐if (mediaPlayer != null) {mediaPlayer.start();currentState=PLAY_STATE_PLAY;startTimer();}}//通知UI界面修改if (mViewController != null){mViewController.onPlayStateChange(currentState);}}/*** 初始化播放器*/private void initPlayer() {if (mediaPlayer == null){mediaPlayer = new MediaPlayer();mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); //利用MediaPlayer来播放MP3格式的音频}}@Overridepublic void stop() { //停止时释放资源Log.d(TAG,"stop");if (mediaPlayer != null && mediaPlayer.isPlaying()) {mediaPlayer.stop();mediaPlayer.release();mediaPlayer=null;stopTimer();currentState=PLAY_STATE_STOP;if (mViewController != null){ //更新播放状态mViewController.onPlayStateChange(currentState);}}}@Overridepublic void seekTo(int seek) {Log.d(TAG,"seekTo"+seek);//播放的进度在0-100之间,需要做一个转换,但是实际的seek应该是一个播放进度的百分比if (mediaPlayer != null ){int tarSeek= (int) (seek * 1.0f / 100 * mediaPlayer.getDuration());mediaPlayer.seekTo(tarSeek); //此时是人为主动控制进度条,改变播放内容}}/*** 播放的时候,开启timerTask*/private void startTimer(){if (timer == null){timer = new Timer(); //设置为成员变量}if (seekTimeTask == null){seekTimeTask=new SeekTimeTask(); //设置为成员变量}timer.schedule(seekTimeTask,0,500); //每500ms更新一次}/*** 停止timerTask*/private void stopTimer(){if (timer != null){timer.cancel(); //不为空时,停止这个timerTasktimer=null;}if (seekTimeTask != null){seekTimeTask.cancel();seekTimeTask=null;}}private class SeekTimeTask extends TimerTask{@Overridepublic void run() {//获取当前的播放进度if(mediaPlayer != null && mViewController != null){int currentPosition = mediaPlayer.getCurrentPosition();int curPosition= (int) (currentPosition * 1.0f /mediaPlayer.getDuration() *100);mViewController.onSeekChange(curPosition);Log.d(TAG,"current play position is "+currentPosition);}}}
}
PlayerService.java
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;import androidx.annotation.Nullable;
import com.example.serviceddemo.presenter.PlayerPresenter;public class PlayerService extends Service {private static final String TAG ="PlayerService" ;private PlayerPresenter playerPresenter;@Overridepublic void onCreate() {Log.d(TAG,"oncreate...");if(playerPresenter == null){ //进行判空,防止重复创建playerPresenter = new PlayerPresenter();}super.onCreate();}@Nullable@Overridepublic IBinder onBind(Intent intent) {Log.d(TAG,"onbind...");return playerPresenter;}@Overridepublic void onDestroy() {Log.d(TAG,"ondestroy...");super.onDestroy();playerPresenter=null;}
}
PlayActivity.java
import androidx.appcompat.app.AppCompatActivity;import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.SeekBar;import com.example.serviceddemo.interfaces.IPlayControl;
import com.example.serviceddemo.interfaces.IPlayerViewControl;
import com.example.serviceddemo.services.PlayerService;import static com.example.serviceddemo.interfaces.IPlayControl.PLAY_STATE_PAUSE;
import static com.example.serviceddemo.interfaces.IPlayControl.PLAY_STATE_PLAY;
import static com.example.serviceddemo.interfaces.IPlayControl.PLAY_STATE_STOP;public class PlayerActivity extends AppCompatActivity {private static final String TAG ="PlayerActivity" ;private SeekBar mseekBar;private Button mPlayOrPause,mClose;private PlayerConnection playerConnection;private IPlayControl iPlayControl;private boolean isUserTouchProgress=false;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_player);initView();initEvent(); //设置相关事件initService(); //开启服务,混合开启服务的方式initBindService(); //绑定服务}/*** 初始化各种控件*/private void initView() {mseekBar=findViewById(R.id.seek_bar);mPlayOrPause=findViewById(R.id.play_or_pause_btn);mClose=findViewById(R.id.close_btn);}/*** 开启服务*/private void initService() {Log.d(TAG,"initService");Intent intent=new Intent(this,PlayerService.class);startService(intent);}/*** 绑定服务(选择混合开启服务的方式!)*/private void initBindService() {Log.d(TAG,"initBindService...");Intent intent=new Intent(this, PlayerService.class);if(playerConnection == null){playerConnection = new PlayerConnection();}bindService(intent,playerConnection,BIND_AUTO_CREATE);}private class PlayerConnection implements ServiceConnection{@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {Log.d(TAG,"onServiceConnected");iPlayControl = (IPlayControl) service;iPlayControl.regiestViewController(mIPlayerViewControl);}@Overridepublic void onServiceDisconnected(ComponentName name) {Log.d(TAG,"onServiceDisconnected");iPlayControl=null;}}/*** 初始化控件的各种事件*/private void initEvent() {mseekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {@Overridepublic void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {//进度条发生改变}@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {//手已经触摸上去了isUserTouchProgress=true;}@Overridepublic void onStopTrackingTouch(SeekBar seekBar) {int touchProgress=seekBar.getProgress();Log.d(TAG,"touchProgress is "+touchProgress);//停止拖动if (iPlayControl != null) {iPlayControl.seekTo(touchProgress);}isUserTouchProgress=false;}});mPlayOrPause.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//播放或者暂停if(iPlayControl != null){iPlayControl.playOrPause();}}});mClose.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//关闭的button被点击了if(iPlayControl != null){iPlayControl.stop();}}});}private IPlayerViewControl mIPlayerViewControl=new IPlayerViewControl() {@Overridepublic void onPlayStateChange(int state) {//播放状态改变时,要根据播放的状态来修改UI,就去定义播放状态switch (state) {case PLAY_STATE_PLAY://播放中的状态:将button显示内容改为“暂停”mPlayOrPause.setText("暂停");break;case PLAY_STATE_PAUSE://暂停中的状态:将button显示内容改为“播放”mPlayOrPause.setText("播放");break;case PLAY_STATE_STOP:mPlayOrPause.setText("播放");break;}}@Overridepublic void onSeekChange(final int seek) {runOnUiThread(new Runnable() {@Overridepublic void run() {if(! isUserTouchProgress){mseekBar.setProgress(seek);}}});}};/*** 解绑服务*/@Overrideprotected void onDestroy() {if(playerConnection != null){unbindService(playerConnection);iPlayControl.unRegiestViewController();Log.d(TAG,"onDestroy");}super.onDestroy();}}
activity_player.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><SeekBarandroid:id="@+id/seek_bar"android:layout_marginTop="10dp"android:layout_width="match_parent"android:max="100"android:layout_height="wrap_content"/><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:layout_marginTop="20dp"android:gravity="center"><Buttonandroid:id="@+id/play_or_pause_btn"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="播放"/><Buttonandroid:id="@+id/close_btn"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="停止"android:layout_marginLeft="50dp"/></LinearLayout>
</LinearLayout>
【Android-Service】基于MVP的音乐播放器demo实现思路(附源码)相关推荐
- jspm伊人静听音乐播放器系统毕业设计(附源码、运行环境)
用户登录界面 歌曲排行榜界面 歌曲大全管理 歌曲排行榜管理 前台首页界面 免费赠送本源代码.数据库,请私信
- JAVA毕业设计Vue.js音乐播放器设计与实现计算机源码+lw文档+系统+调试部署+数据库
JAVA毕业设计Vue.js音乐播放器设计与实现计算机源码+lw文档+系统+调试部署+数据库 JAVA毕业设计Vue.js音乐播放器设计与实现计算机源码+lw文档+系统+调试部署+数据库 本源码技术栈 ...
- Android Service的使用方法 音乐播放器实例
Service翻译成中文是服务,熟悉Windows 系统的同学一定知道很熟悉了.Android里的Service跟Windows里的Service功能差不多,就是一个不可见的进程在后台执行,避免被用户 ...
- 基于JavaSwing开发MP3音乐播放器 课程设计 大作业源码 毕业设计
基于JavaSwing开发MP3音乐播放器: (大作业) 开发环境: Windows操作系统 开发工具: MyEclipse+Jdk 运行效果图: 基于JavaSwing开发MP3音乐播放器: ...
- android音乐播放器上一首,安卓源码(音乐播放器,有播放和下一首,和进度条等功能)...
[实例简介] 安卓音乐播放器,可以完美播放音乐,放下使用,在安卓eclipse下使用. [实例截图] [核心代码] Player └── Player ├── AndroidManifest.xml ...
- Java音乐播放器,窗体程序 完整源码
今天为大家分享一个音乐播放器的开发与制作,目前系统已经完成了初步功能,后续会进一步完善.整个系统界面漂亮,有完整得源码,希望大家可以喜欢.喜欢的帮忙点赞和关注.一起编程.一起进步 开发环境 开发语言为 ...
- 一起用python做个炫酷音乐播放器【V3.0含源码及打包exe】
前言 熟悉的小伙伴都知道,前段时间写了一篇关于音乐播放器的文章–Python自制一款炫酷音乐播放器.不少小伙伴私信我,对播放器提了一些改进建议,对播放器的一些逻辑bug优化完善.今天音乐播放器3.0版 ...
- 一个基于Android开发的简单的音乐播放器
一个基于Android开发的简单的音乐播放器 记得当时老师让我们写因为播放器时,脑子一头雾水,网上杂七杂八的资料也很少有用,因此索性就自己写一篇,希望对有缘人有用. 因为有好多人问我要源码,所以附上g ...
- Android应用--简、美音乐播放器原型放送(作者:小巫)
Android应用--简.美音乐播放器原型放送 2013年7月5日简.美音乐播放器开发 前言:小巫的简.美音乐播放器从5月7号开始开发,之前以为时间很充足,也没有估量整个软件的需求,如果简单实现基本的 ...
最新文章
- COOKIE和SESSION关系和区别
- python教程实例-python教程实例
- DDR3和eMMC区别
- 在Apworks数据服务中使用基于Entity Framework Core的仓储(Repository)实现
- 开发指南专题三:JEECG微云快速开发平台项目编码规范
- Flutter Duration详细概述
- kubenetes 1.4 安装后8080端口无法访问
- 使用python写机器学习算法遇到的问题
- linux查询电信端口,linux下获取电信,网通,铁通IP地址
- 格力空调通讯协议_格力空调485-格力风管机空调内外机单片机RS485通讯协议格式是怎样的-电气资讯 - 电工屋...
- linux下maxwell安装教程,Ubuntu下若干软件的安装方法
- 【win10操作系统基础】我的电脑 控制面板 win10桌面图标有个箭头如何不显示 去掉win10桌面图标箭头的方法
- python实现输入一个正整数_Python中实现输入一个整数的案例
- 5V开关电路应用设计
- CUDA编译(一)---使用nvcc编译cuda
- SHEN ZHEN归来!
- 论文复刻:排污权机制是否提高了企业全要素生产率(附代码、数据、原文献)
- 《权力的游戏》电脑高清壁纸 无水印
- 中国商用割草机市场趋势报告、技术动态创新及市场预测
- android 录像工具,Android 屏幕录制(Surface\ Texture 录制)工具库