关于音乐播放器与系统功能联动功能梳理

主要实现功能:

一、通知栏播放显示和控制

二、系统下拉栏中播放模块显示同步

三、与其他播放器状态同步:本应用播放时暂停其他应用播放,进入其他应用播放时,暂停本应用的后台播放

通知栏播放的显示和控制:

通过Notification + RemoteViews + 广播实现,主要代码如下:
    /*** 初始化自定义通知栏 的按钮点击事件*/private void initRemoteViews() {remoteViews = new RemoteViews(this.getPackageName(), R.layout.notification);//通知栏控制器上一首按钮广播操作Intent intentPrev = new Intent(ACTION_PRE_SONG);PendingIntent prevPendingIntent = PendingIntent.getBroadcast(this, 5100, intentPrev, PendingIntent.FLAG_CANCEL_CURRENT);//为prev控件注册事件remoteViews.setOnClickPendingIntent(R.id.btn_notification_previous, prevPendingIntent);//通知栏控制器播放暂停按钮广播操作  //用于接收广播时过滤意图信息Intent intentPlay = new Intent(ACTION_PAUSE);PendingIntent playPendingIntent = PendingIntent.getBroadcast(this, 5101, intentPlay, PendingIntent.FLAG_CANCEL_CURRENT);//为play控件注册事件remoteViews.setOnClickPendingIntent(R.id.btn_notification_play, playPendingIntent);//通知栏控制器下一首按钮广播操作Intent intentNext = new Intent(ACTION_NEXT_SONG);PendingIntent nextPendingIntent = PendingIntent.getBroadcast(this, 5102, intentNext, PendingIntent.FLAG_CANCEL_CURRENT);//为next控件注册事件remoteViews.setOnClickPendingIntent(R.id.btn_notification_next, nextPendingIntent);//通知栏控制器关闭按钮广播操作Intent intentClose = new Intent(ACTION_PLAY_CLOSE);PendingIntent closePendingIntent = PendingIntent.getBroadcast(this, 5103, intentClose, 0);//为close控件注册事件remoteViews.setOnClickPendingIntent(R.id.btn_notification_close, closePendingIntent);}/*** 初始化通知*/@SuppressLint("NotificationTrampoline")private void initNotification() {String channelId = "play_control";String channelName = "播放控制";int importance = NotificationManager.IMPORTANCE_HIGH;createNotificationChannel(channelId, channelName, importance);//点击整个通知时发送广播Intent intent = new Intent(getApplicationContext(), NotificationClickReceiver.class);PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0,intent, FLAG_UPDATE_CURRENT);//初始化通知notification = new NotificationCompat.Builder(this, "play_control").setContentIntent(pendingIntent).setWhen(System.currentTimeMillis()).setSmallIcon(R.mipmap.ic_launcher).setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))//   .setCustomContentView(remoteViews).setCustomBigContentView(remoteViews).setVisibility(NotificationCompat.VISIBILITY_PUBLIC)// .setStyle(new NotificationCompat.BigTextStyle())//  .setStyle(new NotificationCompat.InboxStyle()).setDefaults(NotificationCompat.DEFAULT_ALL).setAutoCancel(false).setOnlyAlertOnce(true).setOngoing(true).build();}/*** 创建通知渠道** @param channelId   渠道id* @param channelName 渠道名称* @param importance  渠道重要性*/@TargetApi(Build.VERSION_CODES.O)private void createNotificationChannel(String channelId, String channelName, int importance) {NotificationChannel channel = new NotificationChannel(channelId, channelName, importance);channel.enableLights(false);channel.enableVibration(false);channel.setVibrationPattern(new long[]{0});channel.setSound(null, null);manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);manager.createNotificationChannel(channel);}

通知栏整体点击跳转到播放界面:注册全局监听广播

public class NotificationClickReceiver extends BroadcastReceiver {public static final String TAG = "NotificationClickReceiver";@Overridepublic void onReceive(Context context, Intent intent) {LogUtil.showLog(TAG,"通知栏点击");//获取栈顶的Activity// Activity currentActivity = ActivityManager.getCurrentActivity();intent = new Intent(Intent.ACTION_MAIN);intent.addCategory(Intent.CATEGORY_LAUNCHER);intent.setClass(context, MusicPlayerActivity.class);intent.putExtra("from","notify");// intent.putExtra("file",MyApplication.currentPlayMusic);intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);context.startActivity(intent);}
}

系统下拉栏媒体播放信息和状态同步:

通过MediaSession + MediaMetadata + PlaybackState实现

public void initMediaSession(){mediaSession = new MediaSession(this, "music_player_session");mediaSession.setCallback(new MediaSession.Callback() {// 覆盖必要的回调方法,如onPlay, onPause等@Overridepublic void onPause() {super.onPause();mediaSession.setPlaybackState(stateBuilder.setState(PlaybackState.STATE_PAUSED,mPlayer.getCurrentPosition(), 0.0f).build());sendBroadcast(new Intent(ACTION_PAUSE));}@Overridepublic void onPlay() {super.onPlay();mediaSession.setPlaybackState(stateBuilder.setState(PlaybackState.STATE_PLAYING, mPlayer.getCurrentPosition(), 0.0f).build());sendBroadcast(new Intent(ACTION_PLAY_SONG));}@Overridepublic void onSkipToNext() {super.onSkipToNext();sendBroadcast(new Intent(ACTION_NEXT_SONG));}@Overridepublic void onSkipToPrevious() {super.onSkipToPrevious();sendBroadcast(new Intent(ACTION_PRE_SONG));}});mediaSession.setActive(true);metaDataBuilder = new MediaMetadata.Builder();//播放状态stateBuilder = new PlaybackState.Builder();stateBuilder.setActions(PlaybackState.ACTION_PLAY | PlaybackState.ACTION_PAUSE| PlaybackState.ACTION_SKIP_TO_NEXT | PlaybackState.ACTION_SKIP_TO_PREVIOUS);}

状态和信息同步:

    /*** 更改通知的信息和UI*/private Intent intentPlay;private PendingIntent playPendingIntent;public void updateNotificationShow() {//通知栏控制器播放暂停按钮广播操作  //用于接收广播时过滤意图信息intentPlay = new Intent(mPlayer.isPlaying()?ACTION_PAUSE:ACTION_PLAY_SONG);playPendingIntent = PendingIntent.getBroadcast(this, 5101, intentPlay, PendingIntent.FLAG_CANCEL_CURRENT);//为play控件注册事件remoteViews.setOnClickPendingIntent(R.id.btn_notification_play, playPendingIntent);//播放状态判断if (mPlayer.isPlaying()) {remoteViews.setImageViewResource(R.id.btn_notification_play, R.mipmap.notify_pause);} else {remoteViews.setImageViewResource(R.id.btn_notification_play, R.mipmap.notify_play);}//封面专辑remoteViews.setImageViewResource(R.id.iv_album_cover,R.mipmap.ic_launcher);//歌曲名remoteViews.setTextViewText(R.id.tv_notification_song_name,defaultSongName.substring(0,defaultSongName.lastIndexOf(".")));//歌手名remoteViews.setTextViewText(R.id.tv_notification_singer,"");remoteViews.setTextViewText(R.id.tv_duration,StringUtil.formatDuration(mPlayer.getDuration()));remoteViews.setTextViewText(R.id.tv_current_time,StringUtil.formatDuration(mPlayer.getCurrentPosition()));if(mPlayer.getDuration() > 0)remoteViews.setProgressBar(R.id.seekbar,100,mPlayer.getCurrentPosition()*100/mPlayer.getDuration(),false);//发送通知manager.notify(NOTIFICATION_ID,notification);WindowUtils.isNotifyShow = true;//同步下拉栏播放控制区信息metaDataBuilder.putString(MediaMetadata.METADATA_KEY_TITLE,defaultSongName.substring(0,defaultSongName.lastIndexOf(".")));mediaSession.setMetadata(metaDataBuilder.build());}

与其他应用播放器状态同步

通过AudioManager监听onAudioFocusChange音频焦点变化实现

 /** 监测其他应用播放音视频 */mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);mListener = new AudioManager.OnAudioFocusChangeListener() {@Overridepublic void onAudioFocusChange(int focusChange) {LogUtil.showLog(TAG,"==onAudioFocusChange=="+focusChange);abandonAudioFocus(); //禁用音频sendBroadcast(new Intent(ACTION_PAUSE));switch (focusChange) {case AudioManager.AUDIOFOCUS_GAIN:// TBD 继续播放break;case AudioManager.AUDIOFOCUS_LOSS:// TBD 停止播放break;case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:// TBD 暂停播放break;case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:// TBD 混音播放break;default:break;}}};//android 版本 5.0if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {mAttribute = new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build();}//android 版本 8.0if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {mFocusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT).setWillPauseWhenDucked(true).setAcceptsDelayedFocusGain(true).setOnAudioFocusChangeListener(mListener, mHandler).setAudioAttributes(mAttribute).build();}requestAudioFocus();//启动获取音频

效果图:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/850334.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深度学习-11-可变长参数

深度学习-11-可变长参数 本文是《深度学习入门2-自製框架》 的学习笔记,记录自己学习心得,以及对重点知识的理解。如果内容对你有帮助,请支持正版,去购买正版书籍,支持正版书籍不仅是尊重作者的辛勤劳动,也…

Linux 命令 `db_upgrade` 详解与实战

标题:Linux 命令 db_upgrade 详解与实战 在 Linux 系统中,db_upgrade 并不是一个标准的系统命令或广泛认知的数据库升级工具。但在很多自定义的数据库管理系统或应用中,你可能会遇到这样的命令或脚本,用于升级数据库的结构、数据…

数字人实战第一天——最新数字人MuseTalk效果展示

最新数字人MuseTalk效果展示 MuseTalk 是由腾讯团队开发的先进技术,项目地址:GitHub - TMElyralab/MuseTalk: MuseTalk: Real-Time High Quality Lip Synchorization with Latent Space Inpainting,它是一个实时的音频驱动唇部同步模型。该模…

简单通用的系统安装、备份、还原方法,支持 ARM 系统【Ventory+FirePE+DiskGenius】

文章目录 0. 简介1. 制作 Ventory 启动盘1.1. 下载 Ventory1.2. 制作 Ventory 启动盘 2. 添加 FirePE 等系统镜像到启动盘2.1. 下载 FirePE2.2. 导出 .iso 系统镜像文件2.3. .iso 系统镜像文件添加至启动盘 3. 启动 FirePE 等系统镜像3.1. 在 bios 中选择启动盘启动3.2. 启动系…

访问网站时IP被阻止?原因及解决方法

在互联网上,用户可能会面临一个令人困扰的问题——当尝试访问某个特定的网站时,却发现自己的IP地址被该网站屏蔽。 IP地址被网站屏蔽是一个相对常见的现象,而导致这种情况的原因多种多样,包括恶意行为、违规访问等。本文将解释IP地…

4. JavaScript 循环与迭代

JavaScript 中提供了这些循环语句&#xff1a; for 语句do … while 语句while 语句label 语句 跳出多级循环 var num 0; outPoint: for (var i 0; i < 10; i) {for (var j 0; j < 10; j) {if (i 5 && j 5) {break outPoint; // 在 i 5&#xff0c;j 5 …

大学搜题软件网课?推荐五个搜题软件和学习工具 #其他#经验分享#知识分享

大学生活中&#xff0c;选择适合自己的学习工具能够提高学习效率&#xff0c;让学习更加轻松愉快。 1.彩虹搜题 这个是公众号 提供了各大教材以及网课平台的练习题答案&#xff0c;强大的平台支持&#xff0c;无论是智慧树还是MOOC&#xff0c;只有老师们用不到&#xff0c;…

理解JVM内存模型与Java内存模型(JMM)

理解JVM内存模型与Java内存模型&#xff08;JMM&#xff09; 在Java程序的运行过程中&#xff0c;内存管理和线程的同步是两个重要的概念。本文将深入探讨JVM内存模型&#xff08;Java Virtual Machine Memory Model&#xff09;和JMM&#xff08;Java Memory Model&#xff0…

实现开源可商用的 ChatPDF RAG:密集向量检索(R)+上下文学习(AG)

实现 ChatPDF & RAG&#xff1a;密集向量检索&#xff08;R&#xff09;上下文学习&#xff08;AG&#xff09; RAG 是啥&#xff1f;实现 ChatPDF怎么优化 RAG&#xff1f; RAG 是啥&#xff1f; RAG 是检索增强生成的缩写&#xff0c;是一种结合了信息检索技术与语言生成…

型号FM152A,FM148R和利时

型号FM152A,FM148R和利时。控制系统的仿真,综合考虑多方面的因素,本文将用MCGS组态软件设计一个仿真实验监控平台来对其进行实时控制.&#xff0c;完成仿真实验监控平台的设计,型号FM152A,FM148R和利时。最终达到对水箱液位实时监控,实验数据采集,报表的输出和数据的同步显示MC…

TS的高级类型

1.索引类型 学习索引类型 首先要了解keyof(索引查询) Tk 和泛型约束 1.keyof索引查询 就是用来获取某个类型的所有键(键值对的那个键). interface IPerson {name: string;age: number; }type Test keyof IPerson; //name|"age"这就相当于获得了IPerson里面的键也就…

Redis集群搭建(Linux)

安装Redis tar -xzvf redis-6.2.14.tar.gz下载redis wget https://download.redis.io/releases/redis-6.2.14.tar.gz创建目录 cd /home/jnredis mkdir redis 把redis-6.2.14.tar.gz移入/home/jnredis/redis目录下 解压 tar -xzvf redis-6.2.14.tar.gz编译安装 cd redis-…

Live800:深度解析,客户服务如何塑造品牌形象

在当今竞争激烈的市场环境中&#xff0c;品牌形象对于企业的成功至关重要。而客户服务作为品牌与消费者之间最直接的互动方式&#xff0c;不仅影响着消费者的购买决策&#xff0c;更在塑造品牌形象方面发挥着不可替代的作用。本文将深度解析客户服务如何塑造品牌形象&#xff0…

C++协程

什么是协程 协程&#xff08;Coroutine&#xff09;是程序组件&#xff0c;可以在执行过程中暂停并在稍后继续执行。与传统的子例程&#xff08;如函数或过程&#xff09;不同&#xff0c;子例程一旦调用&#xff0c;必须等其返回后才能继续执行调用它的代码。协程则可以在执行…

填充每个节点的下一个右侧节点指针-力扣

本题使用BFS对二叉树进行搜索&#xff0c;然后将每个节点的next指向右侧节点&#xff0c;当节点为一层的最后也给节点时&#xff0c;将其next指向nullptr。 /* // Definition for a Node. class Node { public:int val;Node* left;Node* right;Node* next;Node() : val(0), le…

【Unity3D小功能】Unity3D中UGUI-Text实现打字机效果

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址QQ群&#xff1a;398291828 大家好&#xff0c;我是佛系工程师☆恬静的小魔龙☆&#xff0c;不定时更新Unity开发技巧&#xff0c;觉得有用记得一键三连哦。 一、前言 需求要实现Text的打字机效果&#xff0c;一看居然…

机器学习作业6——svm支持向量机

目录 一、理论 概念&#xff1a; 线性可分&#xff1a; 支持向量&#xff1a; 间隔&#xff1a; 目标&#xff1a; 软间隔&#xff1a; 梯度下降法&#xff1a; 别的方法&#xff1a; 拉格朗日函数&#xff1a; SMO算法&#xff1a; 核函数&#xff1a; 二、代码 …

python代码中参数的默认值

python中的函数&#xff0c;可以给形参指定默认值。 带有默认值的参数&#xff0c;可以在调用的时候不传参。 如上图所示&#xff0c;在给函数设定形参的时候可以给函数形参设定默认值&#xff0c;当然默认参数的形参应该在非默认形参的后面。 如果在调用函数的时候&#xff…

Android输入法IME(三)之 管理端(IMMS)启动流程

2.2. IME管理端&#xff08;IMMS&#xff09;初始化流程 IMMS运行在system server进程中&#xff0c;属于系统服务的一部分&#xff0c;用于控制输入法的显示/隐藏、切换、绑定等操作。 涉及代码文件路径&#xff1a; IMMS运行在system server进程中&#xff0c;属于系统服务的…

Linux云计算架构师涨薪班就业服务有哪些?

学员一站式就业服务:一次学习&#xff0c;薪资翻倍 简历制作与指导 学员在培训期间&#xff0c;人才顾问会提供简历制作和指导服务&#xff0c;帮助学员制作出一份专业、有吸引力的简历。简历是求职者给招聘单位的第一印象&#xff0c;因此非常重要 模拟面试与技巧指导 为了让…