一、先看效果图

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

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,谢谢。

android 本地 播放器,Android 本地播放器相关推荐

  1. android音乐播放器开发 SweetMusicPlayer 播放本地音乐

    代码地址:https://github.com/huweigoodboy/SweetMusicPlayer 上一篇写了加载歌曲列表,http://blog.csdn.net/huweigoodboy/ ...

  2. Android开发本地及网络Mp3音乐播放器(二十)歌曲下载完成后通知主界面更新本地音乐

    转载请注明出处:http://blog.csdn.net/iwanghang/article/details/51448597 项目源码(打赏5积分请点这边):http://download.csdn ...

  3. Android开发本地及网络Mp3音乐播放器(十五)网络音乐及歌词下载功能实现

    实现功能: 实现网络音乐歌词下载功能(下载音乐的同时,下载对应歌词) 下载好的歌词目前不在播放器内,可以通过文件浏览器查看. 后续将博文,将实现本地音乐歌词下载和已下载音乐扫描功能. 因为,没有自己的 ...

  4. Android MediaPlayer 音乐播放器扫描 本地音乐、上一曲、下一曲切歌、播放本地音乐

    Android MediaPlayer 本地音乐播放器 运行截图 项目请在真机(自己的手机)上测试运行,因为我不喜欢用虚拟机. 为了不浪费您的时间,先看一下运行的效果图, 一进去先进行音乐扫描,然后列 ...

  5. Android开发本地及网络Mp3音乐播放器(十二)创建NetMusicListAdapter、SearchResult显示网络音乐列表

    转载请注明出处:http://blog.csdn.net/iwanghang/article/details/51290181 觉得博文有用,请点赞,请留言,请关注,谢谢!~ 实现功能: 实现NetM ...

  6. Android开发本地及网络Mp3音乐播放器(十三)网络音乐搜索功能实现,歌名歌手专辑名搜索

    转载请注明出处:http://blog.csdn.net/iwanghang/article/details/51298411 觉得博文有用,请点赞,请留言,请关注,谢谢!~ 实现功能: 实现网络音乐 ...

  7. Android开发本地及网络Mp3音乐播放器(十八)新下载歌曲加载准备SdcardSearchToList

    转载请注明出处: http://blog.csdn.net/iwanghang/article/details/51395664 觉得博文有用,请点赞,请留言,请关注,谢谢!~ 扫描本地文件加载到it ...

  8. android 根据指定路径获取本地视频列表显示,点击缩略图调用系统播放器进行播放

    第一步,MainActivity.class类代码 如下: package com.learn.lister.systemvediorecord;import android.app.Activity ...

  9. Android开发本地及网络Mp3音乐播放器(十七)已存在歌曲歌词下载

    转载请注明出处: http://blog.csdn.net/iwanghang/article/details/51388896 觉得博文有用,请点赞,请留言,请关注,谢谢!~ 实现功能: 已存在歌曲 ...

  10. Android开发本地及网络Mp3音乐播放器(十)最近播放界面与数据保存更新

    实现功能: 实现MyLoveMusicActivity(音乐收藏界面) 实现MyRecordMusicActivity(最近播放界面) 实现MyMusicListFragment(本地音乐界面)Ite ...

最新文章

  1. 利用runtime实现KVO
  2. 电击、警棍、爆头,被骗去柬埔寨的程序员有多惨?
  3. 暑假第六周总结(2018.8.13-8.19)
  4. 如何利用计算机网络辅助自己,如何借助计算机网络辅助大学英语写作教学.doc...
  5. Annotation processing seems to be disabled for the project microservicecloud
  6. 2022中国素质教育行业报告
  7. VS2005中GridView簡單應用
  8. Core Animation(核心动画)
  9. 登 GitHub 趋势榜首德国疫情追踪 App 号称可保疫情隐私数据无忧,你信吗?
  10. java11下载_Java11 64位下载_Java SE Development Kit 11(JDK11)下载 11.0.0 官方版_当载软件站...
  11. 在 Windows 7 下手动删除驱动程序
  12. excel 图表 保持矢量图格式 粘贴进word
  13. 毕业这么多年,为啥升职加薪这么难?
  14. CSS实现3D正方体动态旋转效果【源码+GIF图】
  15. duilib制作窗体动画效果
  16. java文件读取报(文件名、目录名或卷标语法不正确。)
  17. 去掉Excel自动弹出的粘贴选项按钮
  18. IMX6 / IMX8 系列芯片简单对比
  19. 如何精准查找 Maven 依赖
  20. 【数据结构与算法基础】AOE网络与关键路径

热门文章

  1. 【Spring】Spring Access to DialectResolutionInfo cannot be null when ‘hibernate.dialect‘ not set
  2. 【SpringClould】SpringClould eureka 单机 案例实验
  3. Kafka 与Spark的集成
  4. 【janino】janino 加载自定义函数
  5. 【Flink】Flink ES6写入报错 IncompatibleClassChangeError: Implementing class
  6. IDEA : IDEA 打开使用内存监控
  7. SpringBoot : Consider defining a bean of type xxx in your configuration.
  8. Spark学习-SparkSQL--03-SparkSQL CLI 建表查询出问题
  9. 关于支付回调的一些思考
  10. 完全复制一个dict_关于Excel工作表复制里面列宽的介绍