android 本地 播放器,Android 本地播放器
一、先看效果图
二、项目的播放流程简要介绍
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 本地播放器相关推荐
- android音乐播放器开发 SweetMusicPlayer 播放本地音乐
代码地址:https://github.com/huweigoodboy/SweetMusicPlayer 上一篇写了加载歌曲列表,http://blog.csdn.net/huweigoodboy/ ...
- Android开发本地及网络Mp3音乐播放器(二十)歌曲下载完成后通知主界面更新本地音乐
转载请注明出处:http://blog.csdn.net/iwanghang/article/details/51448597 项目源码(打赏5积分请点这边):http://download.csdn ...
- Android开发本地及网络Mp3音乐播放器(十五)网络音乐及歌词下载功能实现
实现功能: 实现网络音乐歌词下载功能(下载音乐的同时,下载对应歌词) 下载好的歌词目前不在播放器内,可以通过文件浏览器查看. 后续将博文,将实现本地音乐歌词下载和已下载音乐扫描功能. 因为,没有自己的 ...
- Android MediaPlayer 音乐播放器扫描 本地音乐、上一曲、下一曲切歌、播放本地音乐
Android MediaPlayer 本地音乐播放器 运行截图 项目请在真机(自己的手机)上测试运行,因为我不喜欢用虚拟机. 为了不浪费您的时间,先看一下运行的效果图, 一进去先进行音乐扫描,然后列 ...
- Android开发本地及网络Mp3音乐播放器(十二)创建NetMusicListAdapter、SearchResult显示网络音乐列表
转载请注明出处:http://blog.csdn.net/iwanghang/article/details/51290181 觉得博文有用,请点赞,请留言,请关注,谢谢!~ 实现功能: 实现NetM ...
- Android开发本地及网络Mp3音乐播放器(十三)网络音乐搜索功能实现,歌名歌手专辑名搜索
转载请注明出处:http://blog.csdn.net/iwanghang/article/details/51298411 觉得博文有用,请点赞,请留言,请关注,谢谢!~ 实现功能: 实现网络音乐 ...
- Android开发本地及网络Mp3音乐播放器(十八)新下载歌曲加载准备SdcardSearchToList
转载请注明出处: http://blog.csdn.net/iwanghang/article/details/51395664 觉得博文有用,请点赞,请留言,请关注,谢谢!~ 扫描本地文件加载到it ...
- android 根据指定路径获取本地视频列表显示,点击缩略图调用系统播放器进行播放
第一步,MainActivity.class类代码 如下: package com.learn.lister.systemvediorecord;import android.app.Activity ...
- Android开发本地及网络Mp3音乐播放器(十七)已存在歌曲歌词下载
转载请注明出处: http://blog.csdn.net/iwanghang/article/details/51388896 觉得博文有用,请点赞,请留言,请关注,谢谢!~ 实现功能: 已存在歌曲 ...
- Android开发本地及网络Mp3音乐播放器(十)最近播放界面与数据保存更新
实现功能: 实现MyLoveMusicActivity(音乐收藏界面) 实现MyRecordMusicActivity(最近播放界面) 实现MyMusicListFragment(本地音乐界面)Ite ...
最新文章
- 利用runtime实现KVO
- 电击、警棍、爆头,被骗去柬埔寨的程序员有多惨?
- 暑假第六周总结(2018.8.13-8.19)
- 如何利用计算机网络辅助自己,如何借助计算机网络辅助大学英语写作教学.doc...
- Annotation processing seems to be disabled for the project microservicecloud
- 2022中国素质教育行业报告
- VS2005中GridView簡單應用
- Core Animation(核心动画)
- 登 GitHub 趋势榜首德国疫情追踪 App 号称可保疫情隐私数据无忧,你信吗?
- java11下载_Java11 64位下载_Java SE Development Kit 11(JDK11)下载 11.0.0 官方版_当载软件站...
- 在 Windows 7 下手动删除驱动程序
- excel 图表 保持矢量图格式 粘贴进word
- 毕业这么多年,为啥升职加薪这么难?
- CSS实现3D正方体动态旋转效果【源码+GIF图】
- duilib制作窗体动画效果
- java文件读取报(文件名、目录名或卷标语法不正确。)
- 去掉Excel自动弹出的粘贴选项按钮
- IMX6 / IMX8 系列芯片简单对比
- 如何精准查找 Maven 依赖
- 【数据结构与算法基础】AOE网络与关键路径
热门文章
- 【Spring】Spring Access to DialectResolutionInfo cannot be null when ‘hibernate.dialect‘ not set
- 【SpringClould】SpringClould eureka 单机 案例实验
- Kafka 与Spark的集成
- 【janino】janino 加载自定义函数
- 【Flink】Flink ES6写入报错 IncompatibleClassChangeError: Implementing class
- IDEA : IDEA 打开使用内存监控
- SpringBoot : Consider defining a bean of type xxx in your configuration.
- Spark学习-SparkSQL--03-SparkSQL CLI 建表查询出问题
- 关于支付回调的一些思考
- 完全复制一个dict_关于Excel工作表复制里面列宽的介绍