一、先看效果图

二、项目的播放流程简要介绍

1.首先我们需要一个常驻在后台的播放服务,在播放服务中绑定一个播放广播,我们在打开播放器的时候就启动这个播放服务。

public class MusicPlayerService extends Service {

private static final String TAG = MusicPlayerService.class.getName();

public static final String PLAYER_MANAGER_ACTION = "com.lijunyan.blackmusic.service.MusicPlayerService.player.action";

private PlayerManagerReceiver mReceiver;

public MusicPlayerService() {

}

@Override

public IBinder onBind(Intent intent) {

throw new UnsupportedOperationException("Not yet implemented");

}

@Override

public void onCreate() {

super.onCreate();

Log.e(TAG, "onCreate: ");

register();

}

@Override

public void onDestroy() {

super.onDestroy();

Log.e(TAG, "onDestroy: ");

unRegister();

}

@Override

public int onStartCommand(Intent intent, int flags, int startId) {

Log.e(TAG, "onStartCommand: ");

return super.onStartCommand(intent, flags, startId);

}

private void register() {

mReceiver = new PlayerManagerReceiver(MusicPlayerService.this);

IntentFilter intentFilter = new IntentFilter();

intentFilter.addAction(PLAYER_MANAGER_ACTION);

registerReceiver(mReceiver, intentFilter);

}

private void unRegister() {

if (mReceiver != null) {

unregisterReceiver(mReceiver);

}

}

}

2.播放服务中的广播可以接受各种音频控制操作,包括播放、暂停、切歌等。程序在响应用户的音频控制操作时向这个播放广播发送对应的播放、暂停、停止等指令。广播收到不同的指令做不同的功能实现。

public class PlayerManagerReceiver extends BroadcastReceiver {

private static final String TAG = PlayerManagerReceiver.class.getName();

public static final String ACTION_UPDATE_UI_ADAPTER = "com.lijunyan.blackmusic.receiver.PlayerManagerReceiver:action_update_ui_adapter_broad_cast";

private MediaPlayer mediaPlayer;

private DBManager dbManager;

public static int status = Constant.STATUS_STOP;

private int playMode;

private int threadNumber;

private Context context;

public PlayerManagerReceiver() {

}

public PlayerManagerReceiver(Context context) {

super();

this.context = context;

dbManager = DBManager.getInstance(context);

mediaPlayer = new MediaPlayer();

Log.d(TAG, "create");

initMediaPlayer();

}

@Override

public void onReceive(Context context, Intent intent) {

int cmd = intent.getIntExtra(Constant.COMMAND,Constant.COMMAND_INIT);

Log.d(TAG, "cmd = " + cmd);

switch (cmd) {

case Constant.COMMAND_INIT:

Log.d(TAG, "COMMAND_INIT");

break;

case Constant.COMMAND_PLAY:

Log.d(TAG, "COMMAND_PLAY");

status = Constant.STATUS_PLAY;

String musicPath = intent.getStringExtra(Constant.KEY_PATH);

if (musicPath!=null) {

playMusic(musicPath);

}else {

mediaPlayer.start();

}

break;

case Constant.COMMAND_PAUSE:

mediaPlayer.pause();

status = Constant.STATUS_PAUSE;

break;

case Constant.COMMAND_STOP:

NumberRandom();

status = Constant.STATUS_STOP;

if(mediaPlayer!=null) {

mediaPlayer.stop();

}

initStopOperate();

break;

case Constant.COMMAND_PROGRESS://拖动进度

int curProgress = intent.getIntExtra(Constant.KEY_CURRENT, 0);

//异步的,可以设置完成监听来获取真正定位完成的时候

mediaPlayer.seekTo(curProgress);

break;

case Constant.COMMAND_RELEASE:

NumberRandom();

status = Constant.STATUS_STOP;

if(mediaPlayer!=null) {

mediaPlayer.stop();

mediaPlayer.release();

}

break;

}

UpdateUI();

}

private void initStopOperate(){

MyMusicUtil.setShared(Constant.KEY_ID,dbManager.getFirstId(Constant.LIST_ALLMUSIC));

}

private void playMusic(String musicPath) {

NumberRandom();

if (mediaPlayer!=null) {

mediaPlayer.release();

}

mediaPlayer = new MediaPlayer();

mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {

@Override

public void onCompletion(MediaPlayer mp) {

Log.d(TAG, "playMusic onCompletion: ");

NumberRandom(); //切换线程

onComplete(); //调用音乐切换模块,进行相应操作

UpdateUI(); //更新界面

}

});

try {

File file = new File(musicPath);

if(!file.exists()){

Toast.makeText(context,"歌曲文件不存在,请重新扫描",Toast.LENGTH_SHORT).show();

MyMusicUtil.playNextMusic(context);

return;

}

mediaPlayer.setDataSource(musicPath); //设置MediaPlayer数据源

mediaPlayer.prepare();

mediaPlayer.start();

new UpdateUIThread(this, context, threadNumber).start();

} catch (Exception e) {

e.printStackTrace();

}

}

//取一个(0,100)之间的不一样的随机数

private void NumberRandom() {

int count;

do {

count =(int)(Math.random()*100);

} while (count == threadNumber);

threadNumber = count;

}

private void onComplete() {

MyMusicUtil.playNextMusic(context);

}

private void UpdateUI() {

Intent playBarintent = new Intent(PlayBarFragment.ACTION_UPDATE_UI_PlayBar); //接收广播为MusicUpdateMain

playBarintent.putExtra(Constant.STATUS, status);

context.sendBroadcast(playBarintent);

Intent intent = new Intent(ACTION_UPDATE_UI_ADAPTER); //接收广播为所有歌曲列表的adapter

context.sendBroadcast(intent);

}

private void initMediaPlayer() {

NumberRandom(); // 改变线程号,使旧的播放线程停止

int musicId = MyMusicUtil.getIntShared(Constant.KEY_ID);

int current = MyMusicUtil.getIntShared(Constant.KEY_CURRENT);

Log.d(TAG, "initMediaPlayer musicId = " + musicId);

// 如果是没取到当前正在播放的音乐ID,则从数据库中获取第一首音乐的播放信息初始化

if (musicId == -1) {

return;

}

String path = dbManager.getMusicPath(musicId);

if (path == null) {

Log.e(TAG, "initMediaPlayer: path == null");

return;

}

if (current == 0) {

status = Constant.STATUS_STOP; // 设置播放状态为停止

}else {

status = Constant.STATUS_PAUSE; // 设置播放状态为暂停

}

Log.d(TAG, "initMediaPlayer status = " + status);

MyMusicUtil.setShared(Constant.KEY_ID,musicId);

MyMusicUtil.setShared(Constant.KEY_PATH,path);

UpdateUI();

}

public MediaPlayer getMediaPlayer() {

return mediaPlayer;

}

public int getThreadNumber() {

return threadNumber;

}

}

3.项目在播放一个音频的同时维护了一个线程实时去通知界面刷新,该线程从MediaPlayer中获取当前的播放进度、总时间等信息发送给播放界面,播放界面拿到数据就可以刷新播放显示信息了。

public class UpdateUIThread extends Thread {

private static final String TAG = UpdateUIThread.class.getName();

private int threadNumber;

private Context context;

private PlayerManagerReceiver playerManagerReceiver;

private int duration;

private int curPosition;

public UpdateUIThread(PlayerManagerReceiver playerManagerReceiver, Context context, int threadNumber) {

Log.i(TAG, "UpdateUIThread: " );

this.playerManagerReceiver = playerManagerReceiver;

this.context = context;

this.threadNumber = threadNumber;

}

@Override

public void run() {

try {

while (playerManagerReceiver.getThreadNumber() == this.threadNumber) {

if (playerManagerReceiver.status == Constant.STATUS_STOP) {

Log.e(TAG, "run: Constant.STATUS_STOP");

break;

}

if (playerManagerReceiver.status == Constant.STATUS_PLAY ||

playerManagerReceiver.status == Constant.STATUS_PAUSE) {

if (!playerManagerReceiver.getMediaPlayer().isPlaying()) {

Log.i(TAG, "run: getMediaPlayer().isPlaying() = " + playerManagerReceiver.getMediaPlayer().isPlaying());

break;

}

duration = playerManagerReceiver.getMediaPlayer().getDuration();

curPosition = playerManagerReceiver.getMediaPlayer().getCurrentPosition();

Intent intent = new Intent(PlayBarFragment.ACTION_UPDATE_UI_PlayBar);

intent.putExtra(Constant.STATUS, Constant.STATUS_RUN);

intent.putExtra(Constant.KEY_DURATION, duration);

intent.putExtra(Constant.KEY_CURRENT, curPosition);

context.sendBroadcast(intent);

}

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}catch (Exception e){

e.printStackTrace();

}

}

}

三、项目文件结构

四、其他

如果对你有帮助的话,可以给我github个star,谢谢。

注:本文著作权归作者,由demo大师发表,拒绝转载,转载需要作者授权

android 酷狗demo_Android 本地播放器相关推荐

  1. 酷狗html5排行,轻享音乐 酷狗全新HTML5播放器低调发布

    近日老牌数字音乐厂商酷狗音乐推出了基于HTML5的手机端播放器,跨平台使用,且无需安装,手机浏览器输入相应网址(m.kugou.com)即可实现音频播放. 酷狗html5播放器主界面 这是目前国内第一 ...

  2. android 酷狗demo_Android仿酷狗旋转界面功能-自定义控件实现

    引言 该旋转界面主要是仿照IOS酷狗版的旋转界面来实现,本项目通过结合ValueAnimator.Rotation.PivotX和PivotY来实现,目前主要实现了左旋转和右旋转,该功能主要是在我的乐 ...

  3. android 酷狗demo_Android仿酷狗音乐自定义侧滑菜单控件简单实现

    随着Android的不断成熟,许多绚丽的效果也在不断的被大家开发出来,其中侧滑的效果用到的项目很多,用的好的更是给吸引了很多用户.国内像QQ和酷狗App的侧滑就很给力,所以查了一些资料,并结合View ...

  4. android 酷狗demo_Android仿酷狗皮肤预览界面的实现(利用canvas缩放的原理)

    GitHub_ AnJiaoDe/Scale-Master APKdemo_ AnJiaoDe/Scale-Master/blob/master/app/build/outputs/apk/app-d ...

  5. android 酷狗demo_Android仿酷狗音乐SeekBar——样式篇

    Android仿酷狗音乐SeekBar 需求:仿酷狗音乐SeekBar 直接上图,上代码 1903148-676fcbf2e5048392.png 1903148-d3e5ab81fa2acd42.p ...

  6. 酷狗外链播放器html5,仿酷狗html5手机音乐播放器主要部分代码

    HTML5作品,经测试,效果确定不错,遗憾的是只支持谷歌和苹果等以webkit核心的浏览器,网友体验的时候请使用谷歌等浏览器来运行,不然的话无法看到效果,不说了,看效果吧 复制代码 代码如下: 主要部 ...

  7. android 酷狗demo_酷狗音乐Android客户端详细使用评测

    曾经现在酷狗音乐一直是PC机上必装的音乐播放软件,手机音乐播放器哪个好用呢,酷狗音乐Android客户端也经过几个版本更新,版酷狗音乐的功能,界面都趋于完美.下面来看看酷狗音乐Android客户端详细 ...

  8. 实现 酷狗音乐 歌词播放效果

    今天将为大家带来 粗略版 酷狗音乐 歌词播放的效果.我们一步一步来.首先做这个是因为有一次公司项目中需要做一个汽车扫描效果的时候,想到来做这个歌词播放效果的.那么我们这次先上效果图: 好的上面的文字是 ...

  9. Android应用开发--MP3音乐播放器滚动歌词实现

    Android应用开发--MP3音乐播放器滚动歌词实现 2013年6月2日  简.美音乐播放器开发记录 -----前话 有网友给我博客评论说,让我借鉴好的Android代码,代码贴出来的时候最好整体先 ...

最新文章

  1. ASP.NET比较常用的26个性能优化技巧
  2. Deep Residual Learning for Image Recognition个人有感
  3. 什么?IP协议是什么你竟然不了解,那还不快快点进来!
  4. python的easygui_Python的easygui学习
  5. [leetcode]1.Two Sum
  6. 有效利用番茄工作法提高效率--XorTime的使用方法
  7. 从os.cpus()来分析nodejs源码结构
  8. Spring与MyBatis整合源码分析
  9. 【解决】如何将腾讯QLV格式的视频转换成MP4
  10. 物联网--解决ESP8266与电脑串口通讯
  11. MTK G-sensor
  12. Matlab 仿真——直流电机速度控制(3)PID控制器设计
  13. PCB设计中,如何快速消除PCB布线?
  14. 拓嘉辰丰:拼多多直通车推广常见问题解析
  15. 如何用好示波器?资深工程师也会忽略这些细节……
  16. Redis Expire 设置key过期时间
  17. Android 调用地图导航
  18. 微信小程序实现商城案例(赋源码)
  19. 信雅达,一家不尊重应聘者的公司
  20. element-ui中tree组件双击事件的实现

热门文章

  1. 用STM32的内置DAC制作一个波形生成器(发生器)
  2. iJ配置Maven环境详解
  3. 借鉴《观沧海》作现代爱情诗一篇
  4. github添加密钥
  5. [机器学习、Spark]Spark MLlib实现数据基本统计
  6. 使用 HTTP/POST 进行 Internet/分布式计算
  7. Idhttp ,cookie相关
  8. 一把王者荣耀的时间打卡剑指 Offer简单入门题
  9. 让我们了解一下VOL,VLK,OEM的意思
  10. 如何培养一个人敏锐的判断力