关于媒体浏览器服务(MediaBrowserService)
来源:互联网 发布:透明屏幕软件下载 编辑:程序博客网 时间:2024/06/10 14:37
今天说的这个主题与媒体播放有关,尤其是音乐播放,说到音乐播放大家应该都用过音乐App。
通常一个音乐App的实现主要涉及如下几点:
1. 从服务器获取音乐数据
2. 播放音乐时播放器的各种播放状态以及不同状态下的UI展示
3. 播放过程中通过UI界面控制播放器的各种状态
4. UI控制如何与播放服务进行关联并进行状态同步
4. 如何保证后台播放过程中播放服务不被杀死
对于上面的这几点,其实Android
已经为我们提供了一套完整的解决方案,它已经很好的将这些操作进行了封装,我们只需要关注数据的获取和歌曲的播放即可。Android
提供的这套API在support-v4
中提供了兼容版本,因此在使用的过程中最好使用该版本以兼容低版本系统。
关键类主要有如下几个:
1. MediaBrowserServiceCompat
媒体浏览器服务
2. MediaBrowserCompat
媒体浏览器
2. MediaControllerCompat
媒体控制器
3. MediaSessionCompat
媒体会话
我们一个个来说。
MediaBrowserServiceCompat
该类有两个作用:
1. 音乐播放后台服务
2. 客户端中获取音乐数据的服务,所有的音乐数据都通过该服务与服务端进行交互获取(或者直接获取手机中的本地音乐数据)
既然知道该类是Service
的子类实现,所以说它是音乐播放的后台服务也好理解,但是该类作为一个后台播放服务却不是通过其自身直接实现的,而是通过MediaSessionCompat
媒体会话这个类来实现的。在使用过程中媒体会话会与该服务关联起来,所有的播放操作都交由MediaSessionCompat
实现。
而对于获取数据,则是通过MediaBrowserServiceCompat
的如下两个方法来进行控制:
@Overridepublic BrowserRoot onGetRoot(@NonNull String clientPackageName, int clientUid, Bundle rootHints) { /** * 在返回数据之前,可以进行黑白名单控制,以控制不同客户端浏览不同的媒体资源 * */ if(!PackageUtil.isCallerAllowed(this, clientPackageName, clientUid)) { return new BrowserRoot(null, null); } //此方法只在服务连接的时候调用 //返回一个rootId不为空的BrowserRoot则表示客户端可以连接服务,也可以浏览其媒体资源 //如果返回null则表示客户端不能流量媒体资源 return new BrowserRoot(BrowserRootId.MEDIA_ID_ROOT, null);}@Overridepublic void onLoadChildren(@NonNull String parentId, @NonNull Result<List<MediaItem>> result) { /*** * 此方法中的parentId与上面的方法onGetRoot中返回的RootId没有关系 * 客户端连接后,它可以通过重复调用MediaBrowserCompat.subscribe() 方法来发起数据获取请求。 * 而每次调用subscribe() 方法都会发送一个onLoadChildren()回调到该service中,然后返回一个MediaBrowser.MediaItem(音乐数据) 对象列表 * * 每个MediaItem 都有唯一的ID字符串,它其实是一个隐式的token。 * 当客户想打开子菜单或播放一个item时,它就将ID传入。 */ if(BrowserRootId.MEDIA_ID_MUSIC_LIST_REFRESH.equals(parentId)) { //在当前方法执行结束返回之前必须要调用result.detach(),否则无法发起请求 result.detach(); MusicProvider.getInstance().requestMusic(result); //如果想要通过http请求来获取数据,则必须按照上面说的必须要先调用result.detach();方法,否则会出现异常。http请求结束之后则通过调用result.sendResult(mMetadataCompatList);将数据返回,返回的数据在注册的接口MediaBrowserCompat.SubscriptionCallback中通过回调拿到在界面上进行展示 //而且此处返回的数据类型必须是MediaBrowser.MediaItem } else { result.detach(); }}
MediaBrowserCompat
前面说过MediaBrowserServiceCompat
(媒体浏览服务)是作为数据请求服务来获取数据的,因此相应的会有一个媒体浏览客户端来发起媒体数据的获取请求,该类就是这个客户端。
前面已经介绍过通过调用MediaBrowserCompat.subscribe()
方法来发起数据请求,而在调用此方法之前,必须保证MediaBrowserCompat
连接上媒体浏览服务,连接方式如下:
//通过如下代码连接MediaBrowserServiceCompat,连接成功后获取媒体会话token//通过媒体会话token创建MediaControllerCompat //这时就将MediaControllerCompat与媒体会话MediaSessionCompat关联起来了MediaBrowserCompat mediaBrowser = new MediaBrowserCompat(this, new ComponentName(this, MusicService.class), mConnectionCallback, null);//连接媒体浏览服务成功后的回调接口final MediaBrowserCompat.ConnectionCallback mConnectionCallback = new MediaBrowserCompat.ConnectionCallback() { @Override public void onConnected() { try { //获取与MediaBrowserServiceCompat关联的媒体会话token MediaSessionCompat.Token token = mMediaBrowser.getSessionToken(); //通过媒体会话token创建媒体控制器并与之关联 //关联之后媒体控制器就可以控制播放器的各种播放状态了 MediaControllerCompat mediaController = new MediaControllerCompat(this, token); //将媒体控制器与当前上下文Context进行关联 //此处关联之后,我们在界面上操作某些UI的时候就可以通过当前上下文Context来获取当前的MediaControllerCompat //MediaControllerCompat controller = MediaControllerCompat.getMediaController((Activity) context); MediaControllerCompat.setMediaController(this, mediaController); //为媒体控制器注册回调接口 mediaController.registerCallback(mMediaControllerCallback); } catch (RemoteException e) { onMediaControllerConnectedFailed(); } } };//媒体控制器控制播放过程中的回调接口final MediaControllerCompat.Callback mMediaControllerCallback = new MediaControllerCompat.Callback() { @Override public void onPlaybackStateChanged(@NonNull PlaybackStateCompat state) { //播放状态发生改变时的回调 onMediaPlayStateChanged(state); } @Override public void onMetadataChanged(MediaMetadataCompat metadata) { if(metadata == null) { return; } //播放的媒体数据发生变化时的回调 onPlayMetadataChanged(metadata); } };//发起数据请求 //先解除订阅 mediaBrowser.unsubscribe(BrowserRootId.MEDIA_ID_MUSIC_LIST_REFRESH); //重新对BrowserRootId进行订阅 //调用此方法后,会接着执行MusicService中的onGetRoot方法和onLoadChildren方法 //onGetRoot方法(只会调用一次)决定是否允许当前客户端连接服务和获取媒体数据 //如果允许连接服务同时也允许获取媒体数据,则会接着调用onLoadChildren方法开始获取数据 //数据获取成功后会调用订阅的回调接口将数据返回回来 mediaBrowser.subscribe(BrowserRootId.MEDIA_ID_MUSIC_LIST_REFRESH, mSubscriptionCallback);//向媒体流量服务发起媒体浏览请求的回调接口final MediaBrowserCompat.SubscriptionCallback mSubscriptionCallback = new MediaBrowserCompat.SubscriptionCallback() { @Override public void onChildrenLoaded(@NonNull String parentId, @NonNull List<MediaBrowserCompat.MediaItem> children) { //数据获取成功后的回调 } @Override public void onError(@NonNull String id) { //数据获取失败的回调 } };
MediaSessionCompat
前面说过MediaBrowserServiceCompat
的媒体播放其实是通过关联的MediaSessionCompat
来实现的,而其关联方式也很简单:
MediaSessionCompat mSession = new MediaSessionCompat(this, "MusicService");setSessionToken(mSession.getSessionToken());mSession.setCallback(new MediaSessionCompat.Callback());mSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);//MediaSessionCompat的播放控制则又全部是通过接口MediaSessionCompat.Callback来实现的@Override public void onPlay() {//点击播放按钮时触发//通过MediaControllerCompat .getTransportControls().play();触发 } @Override public void onSkipToQueueItem(long queueId) { //播放指定对列媒体时触发 //通过MediaControllerCompat .getTransportControls().onSkipToQueueItem(queueId);触发 } @Override public void onSeekTo(long position) { //设置到指定进度时触发 //MediaControllerCompat.getTransportControls().seekTo(position); } @Override public void onPlayFromMediaId(String mediaId, Bundle extras) {//播放指定媒体数据时触发//MediaControllerCompat.getTransportControls().playFromMediaId(mediaItem.getMediaId(), null); } @Override public void onPause() {//暂停时触发//MediaControllerCompat.getTransportControls().pause(); } @Override public void onStop() {//停止播放时触发//MediaControllerCompat.getTransportControls().stop(); } @Override public void onSkipToNext() {//跳到下一首时触发//MediaControllerCompat.getTransportControls().skipToNext(); } @Override public void onSkipToPrevious() {//跳到上一首时触发//MediaControllerCompat.getTransportControls().skipToPrevious(); }//当然还有很多回调函数,大家可以自行查看}
MediaControllerCompat
媒体控制器在上面已经介绍了其创建和关联方式,而它控制播放器状态的方式在上面的代码注释中已经说明了,基本上都是通过MediaControllerCompat.getTransportControls()
来进行控制的。
到这里媒体服务的相关使用和注意点已经介绍完了,使用这套api来实现音乐APP还是很方便很快捷的,而且我们可以很方便的切换播放器,如MediaPlayer
,ExoPlayer
等,如有建议和问题欢迎在博客关于页中扫码加QQ群交流。
- 关于媒体浏览器服务(MediaBrowserService)
- Android API Guide for Media Apps(四)—— 构建媒体浏览器服务(Building a Media Browser Service)
- 关于“媒体查询”
- 关于媒体查询
- 关于媒体查询
- 媒体服务频道访问控制
- 关于实现使用浏览器获取gsoap服务wsdl的实现
- 浏览器中流媒体(rtsp)播放
- BUG:记MediaBrowserService的onLoadChildren不执行
- ffmpeg+ffserver媒体服务搭建小记
- ffmpeg+ffserver媒体服务搭建小记
- ffmpeg+ffserver媒体服务搭建小记
- JW Player 现在支持 Azure 媒体服务
- 通过 Azure 媒体服务进行高速编码
- ffmpeg+ffserver媒体服务搭建小记
- ffmpeg+ffserver媒体服务搭建小记
- 中国Azure媒体服务RESTAPI的Endpoint
- 中国Azure媒体服务RESTAPI的Endpoint
- 【精华版】前缀式、中缀式、后缀式
- 《笨办法学python》--打印,打印
- java线程池-2
- Java中关于&与&&,|和||的区别
- 月薪3万的程序员都避开了哪些坑
- 关于媒体浏览器服务(MediaBrowserService)
- HTML和CSS —— 1(网页初识)
- Intellij IDEA中创建Spark项目
- python读取unicode编码txt文件
- 关于java线程的几个小知识点(后续慢慢提供源码和详解分析)
- 暂停更新博客(1705-1711)须知
- 图解http学习笔记5.与HTTP协作的web服务器
- Github代码仓创建及更新
- 文档特征提取