如何快速开发一款音乐播放器?
文末提供体验demo,实现了播放控制,进度更新,全网音乐免费下载,欢迎技术交流!
音乐播放器无非就是对mediaplayer对象的操作了,当然需要开启服务,而服务为了保活,只能使用前台服务。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(new Intent(mContext, MusicService.class));
} else {
startService(new Intent(mContext, MusicService.class));
}
启动前台服务后,你有5秒的时间发送服务通知,否则服务会被杀死并抛出异常
@Override
public void onCreate() {
super.onCreate();
// 服务通知
mNotification = createForegroundNotification();
//将服务置于启动状态 ,NOTIFICATION_ID指的是创建的通知的ID
startForeground(mNotificationId, mNotification);
创建服务通知
/**
* 创建服务通知
*/
private Notification createForegroundNotification() {
mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// 唯一的通知通道的id.
String notificationChannelId = "notification_channel_music";
// Android8.0以上的系统,新建消息通道
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
//用户可见的通道名称
String channelName = "音乐播放";
//通道的重要程度
int importance = NotificationManager.IMPORTANCE_NONE;
NotificationChannel notificationChannel = new NotificationChannel(notificationChannelId, channelName, importance);
notificationChannel.setDescription("音乐播放控制器");
//LED灯
notificationChannel.enableLights(false);
// notificationChannel.setLightColor(Color.RED);
//震动
notificationChannel.setVibrationPattern(new long[]{0});
notificationChannel.enableVibration(false);
//声音
notificationChannel.setSound(null,null);
mNotificationManager.createNotificationChannel(notificationChannel);
}
mRemoteView = new RemoteViews(getPackageName(), R.layout.notification);
initRemoteView(mRemoteView);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, notificationChannelId)
.setTicker("ticket")
.setOngoing(true)//禁止侧滑删除
//通知小图标
.setSmallIcon(R.mipmap.logo)
.setCustomContentView(mRemoteView)
.setCustomBigContentView(mRemoteView)
.setOnlyAlertOnce(true)//只响铃一次
.setPriority(NotificationCompat.PRIORITY_LOW);//次要级通知,避免更新通知不断发出声音
// 创建通知并返回
return builder.build();
}
如何实现音乐的控制,通知栏控制器和app页面的控制器如何同步?
那么就要使用广播机制了,这里我定义了一些抽象方法,然后在BroadcastReceiver中处理这些事件
public abstract class MusicCallback{
public void init(Context context, Intent intent) {}
public void inited(Context context, Intent intent){}
public void onMusicStart(Context context, Intent intent){}
public void onMusicError(Context context, Intent intent){}
public void onMusicRemove(Context context, Intent intent){}
public void onMusicRemoveAll(Context context, Intent intent){}
public void onMusicProgressUpdate(Context context, Intent intent){}
public void clickPlayThisObj(Context context, Intent intent){}
public void clickPlayListAddButton(Context context, Intent intent){}
public void clickPlayButton(Context context, Intent intent){}
public void clickPlayBeforeButton(Context context, Intent intent){}
public void clickPlayAfterButton(Context context, Intent intent){}
public void clickPlayModeButton(Context context, Intent intent){}
}
其实就是一些交互事件的方法,主要有,播放,上一曲,下一曲,模式切换(单曲/多曲循环)等等。这些基本满足了一个音乐控制器所有的交互事件!
然后在需要音乐控制器的地方实现以下代码可以实现交互了:
mReceiver = new MusicBroadcastReceiver(mContext, mMusicDialogCallback)
.addFilter(MusicOpra.MUSIC_START)
.addFilter(MusicOpra.MUSIC_ERROR)
.addFilter(MusicOpra.MUSIC_LIST_ADD)
.addFilter(MusicOpra.MUSIC_PROGRESS_UPDATE)
.addFilter(MusicOpra.MUSIC_INITED)
.register();
@Override
protected void onClickEvent(View view) {
switch (view.getId()){
case R.id.playIv:
mContext.sendBroadcast(new Intent(MusicOpra.MUSIC_PLAY_PAUSE));
break;
case R.id.playBeforeIv:
mContext.sendBroadcast(new Intent(MusicOpra.MUSIC_PLAY_BEFORE));
break;
case R.id.playAfterIv:
mContext.sendBroadcast(new Intent(MusicOpra.MUSIC_PLAY_AFTER));
break;
case R.id.playModeIv:
mContext.sendBroadcast(new Intent(MusicOpra.MUSIC_PLAY_MODE));
break;
}
}
private MusicCallback mMusicDialogCallback = new MusicCallback() {
private SingBean mSingBean;
private boolean isPrepared;
private boolean isPlaying;
private int playMode;
@Override
public void inited(Context context, Intent intent) {
mSingBean = (SingBean) intent.getSerializableExtra(MusicOpra.KEY_MUSIC_BEAN);
isPrepared = intent.getBooleanExtra(MusicOpra.KEY_MUSIC_PREPARED, false);
isPlaying = intent.getBooleanExtra(MusicOpra.KEY_MUSIC_ISPLAYING, false);
playMode = intent.getIntExtra(MusicOpra.KEY_MUSIC_PLAY_MODE, 0);
if (playMode == 0) {
playModeIv.setImageResource(R.drawable.icon_turn_all);
} else {
playModeIv.setImageResource(R.drawable.icon_turn_single);
}
if (isPlaying) {
playIv.setImageResource(R.drawable.pause);
} else {
playIv.setImageResource(R.drawable.play);
}
if (mSingBean!=null){
singNameTv.setText(mSingBean.getSingName());
}
progressBar.setProgress(intent.getIntExtra(MusicOpra.KEY_MUSIC_PROGRESS, 0));
}
@Override
public void clickPlayButton(Context context, Intent intent) {
if (mSingBean != null) {
if (isPrepared) {
if (!isPlaying) {
playIv.setImageResource(R.drawable.pause);
isPlaying = true;
} else {
playIv.setImageResource(R.drawable.play);
isPlaying = false;
}
} else {
mContext.sendBroadcast(new Intent(MusicOpra.MUSIC_PLAY_THIS).putExtra(MusicOpra.KEY_MUSIC_BEAN, mSingBean));
}
} else {
mContext.sendBroadcast(new Intent(MusicOpra.MUSIC_ERROR).putExtra(MusicOpra.KEY_MUSIC_ERROR, MusicService.MUSIC_ERROR_NODATA));
}
}
@Override
public void clickPlayModeButton(Context context, Intent intent) {
if (playMode == 0) {//当前是多曲循环
playModeIv.setImageResource(R.drawable.icon_turn_single);
playMode = 1;
} else {
playModeIv.setImageResource(R.drawable.icon_turn_all);
playMode = 0;
}
}
@Override
public void clickPlayListAddButton(Context context, Intent intent) {
if (getActivity() instanceof MainActivity){
ToastUtil.showShort(mContext, "已添加到播放列表");
}
}
@Override
public void onMusicStart(Context context, Intent intent) {
isPrepared = true;
isPlaying=true;
mSingBean = (SingBean) intent.getSerializableExtra(MusicOpra.KEY_MUSIC_BEAN);
singNameTv.setText(mSingBean.getSingName());
playIv.setImageResource(R.drawable.pause);
progressBar.setProgress(0);
}
@Override
public void onMusicError(Context context, Intent intent) {
//播放错误
switch (intent.getIntExtra(MusicOpra.KEY_MUSIC_ERROR, 1)) {
case MediaPlayer.MEDIA_ERROR_IO:
singNameTv.setText("无法播放:MEDIA_ERROR_IO");
case MediaPlayer.MEDIA_ERROR_SERVER_DIED:
singNameTv.setText("无法播放:MEDIA_ERROR_SERVER_DIED");
break;
case MediaPlayer.MEDIA_ERROR_TIMED_OUT:
singNameTv.setText("无法播放:MEDIA_ERROR_TIMED_OUT");
break;
case MediaPlayer.MEDIA_ERROR_UNKNOWN:
case MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK://无效的进度操作
singNameTv.setText("无法播放:MEDIA_ERROR_UNKNOWN");
break;
case MediaPlayer.MEDIA_ERROR_UNSUPPORTED://不支持的格式
case MediaPlayer.MEDIA_ERROR_MALFORMED://码流有问题,不支持
singNameTv.setText("无法播放:MEDIA_ERROR_UNSUPPORTED");
break;
case MusicService.MUSIC_ERROR_NODATA:
singNameTv.setText("播放列表无可播放歌曲!");
break;
}
playIv.setImageResource(R.drawable.play);
}
@Override
public void onMusicProgressUpdate(Context context, Intent intent) {
int progress = intent.getIntExtra(MusicOpra.KEY_MUSIC_PROGRESS, 0);
progressBar.setProgress(progress);
}
以上是音乐播放器的实现思路。
源码已在gitee上开源,欢迎一起技术交流学习!
https://gitee.com/jhone/music