前言
Android 5.0开始引入的媒体应用框架,分为媒体控制器MediaController(用于界面UI)和媒体会话MediaSession(用于播放器Player)。MediaSession框架,使用一套接口,减少了很多流程的繁琐和service的通信等,实现多个设备或者UI的统一调用,其代码可读性、结构耦合度(解耦UI和播放器:MediaPlayer、ExoPlayer等)方面都控制得非常好。
本文简单的介绍一下MediaSession框架的使用。
记录于此,方便自己查阅。
正文
MediaSession框架主要如下几个类:
媒体浏览器,用来连接媒体服务MediaBrowserService和订阅数据,在注册的回调接口中我们就可以获取到Service的连接状态、获取音乐数据。一般在客户端中创建。
MediaBrowserService
媒体服务,它有两个关键的回调函数onGetRoot()和onLoadChildren()
onGetRoot():控制客户端媒体浏览器的连接请求,返回值中决定是否允许连接
onLoadChildren():媒体浏览器向服务器发送数据订阅请求时会被调用,一般在这里执行异步获取数据的操作,然后在将数据发送回媒体浏览器注册的接口中。
MediaSession
媒体会话,受控端,通过设置MediaSessionCompat.Callback回调来接收MediaController发送的指令,收到指令后会触发Callback中的回调方法,比如播放暂停等。
Session一般在MediaBrowserService.onCreate方法中创建,最后需调用setSessionToken方法设置用于和控制器配对的令牌并通知浏览器连接服务成功。
MediaController
媒体控制器,在客户端中工作,通过控制器向媒体服务器发送指令,然后通过MediaControllerCompat.Callback设置回调函数来接受服务端的状态。
MediaController创建时需要受控端的配对令牌,因此需要在浏览器连接成功后才进行MediaController的创建。
PlaybackState
封装了各种播放状态。
MediaMetadata
保存当前播放媒体的信息,比如专辑,艺术家,总时间长度。
公共部分
Common.java
public class Common { //Media服务相关包名 public static final String MEDIA_SERVICE_PACKAGE = "com.biumall.service"; public static final String MEDIA_SERVICE_NAME = "com.biumall.service.MediaService"; //参考Android原生LocalMedia中的 public static final String ROOT_ID = "__ROOT__"; public static final String FOLDERS_ID = "__FOLDERS__"; public static final String ARTISTS_ID = "__ARTISTS__"; public static final String ALBUMS_ID = "__ALBUMS__"; public static final String GENRES_ID = "__GENRES__"; }
主要是放客户端和服务端公共的资源或配置。
服务端
在使用时,需要主动或提前启动MediaService。
MediaService.java
public class MediaService extends MediaBrowserService { private final String TAG = MediaApp.TAG + getClass().getSimpleName(); private MediaSession mMediaSession; @Override public void onCreate() { super.onCreate(); //创建MediaSession对象 mMediaSession = new MediaSession(this, TAG); // 设置token后会触发MediaBrowser.ConnectionCallback的回调方法 // 表示MediaBrowser与MediaBrowserService连接成功 setSessionToken(mMediaSession.getSessionToken()); //设置控制回调 mMediaSession.setCallback(callback); } @Override public void onDestroy() { super.onDestroy(); //退出就释放 if (null != mMediaSession) { mMediaSession.setCallback(null); mMediaSession.release(); mMediaSession = null; } } @Nullable @Override public BrowserRoot onGetRoot(@NonNull String clientPackageName, int clientUid, @Nullable Bundle rootHints) { //设置默认的parentId=ROOT_ID //客户端mMediaBrowser.getRoot()返回的默认MediaID return new BrowserRoot(Common.ROOT_ID, null); } @Override public void onLoadChildren(@NonNull String parentId, @NonNull Result<List<MediaBrowser.MediaItem>> result) { //根据parentId查询对应数据,通过result返回到UI界面 switch (parentId) { case Common.ROOT_ID: break; case Common.FOLDERS_ID: break; case Common.ALBUMS_ID: break; case Common.ARTISTS_ID: break; case Common.GENRES_ID: break; default: break; } } public MediaSession.Callback callback = new MediaSession.Callback() { //响应MediaButton按键 @Override public boolean onMediaButtonEvent(@NonNull Intent mediaButtonIntent) { return super.onMediaButtonEvent(mediaButtonIntent); } //下面部分响应MediaController.getTransportControls()调用 @Override public void onPlay() { super.onPlay(); } //播放指定mediaId的媒体 @Override public void onPlayFromMediaId(String mediaId, Bundle extras) { super.onPlayFromMediaId(mediaId, extras); } //暂停 @Override public void onPause() { super.onPause(); } //下一曲 @Override public void onSkipToNext() { super.onSkipToNext(); } //上一曲 @Override public void onSkipToPrevious() { super.onSkipToPrevious(); } //跳到指定进度 @Override public void onSeekTo(long pos) { super.onSeekTo(pos); } //等还有很多接口 }; }
AndroidManifest.xml
<service android:name=".MediaService" android:exported="true"> <intent-filter> <action android:name="android.media.browse.MediaBrowserService" /> </intent-filter> </service>
客户端
MainActivity
public class MainActivity extends AppCompatActivity { private MediaBrowser mMediaBrowser; private String mMediaId = null; private MediaController mMediaController; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mMediaBrowser = new MediaBrowser(this, new ComponentName(Common.MEDIA_SERVICE_PACKAGE, Common.MEDIA_SERVICE_NAME), connectionCallback, null); //绑定服务 mMediaBrowser.connect(); } @Override protected void onDestroy() { super.onDestroy(); //注销状态回调 if (null != mMediaController) { mMediaController.unregisterCallback(mediaControllerCallback); mMediaController = null; } //注销订阅和解除服务绑定 if (null != mMediaBrowser) { mMediaBrowser.unsubscribe(mMediaId); mMediaBrowser.disconnect(); } } //connect callback private final MediaBrowser.ConnectionCallback connectionCallback = new MediaBrowser.ConnectionCallback() { @Override public void onConnectionFailed() { super.onConnectionFailed(); //连接失败 } @Override public void onConnected() { super.onConnected(); //连接成功 if (mMediaBrowser.isConnected()) { //获取默认MediaId mMediaId = mMediaBrowser.getRoot(); //取消订阅 mMediaBrowser.unsubscribe(mMediaId); //订阅 mMediaBrowser.subscribe(mMediaId, subscriptionCallback); //创建MediaController对象并注册监听 mMediaController = new MediaController(MainActivity.this, mMediaBrowser.getSessionToken()); mMediaController.registerCallback(mediaControllerCallback); } } }; private final MediaBrowser.SubscriptionCallback subscriptionCallback = new MediaBrowser.SubscriptionCallback() { @Override public void onChildrenLoaded(@NonNull String parentId, @NonNull List<MediaBrowser.MediaItem> children) { super.onChildrenLoaded(parentId, children); //返回订阅的MediaId的数据 } @Override public void onError(@NonNull String parentId) { super.onError(parentId); } }; private MediaController.Callback mediaControllerCallback = new MediaController.Callback() { @Override public void onPlaybackStateChanged(@Nullable PlaybackState state) { super.onPlaybackStateChanged(state); //播放状态的更新(播放状态,进度等) } @Override public void onMetadataChanged(@Nullable MediaMetadata metadata) { super.onMetadataChanged(metadata); //媒体信息(艺术家,专辑图,总时长) } }; }
MediaController
MediaController是用于控制服务的播放状态。
if (null != mMediaController) { //下一曲 mMediaController.getTransportControls().skipToNext(); //上一曲 mMediaController.getTransportControls().skipToPrevious(); //播放 mMediaController.getTransportControls().play(); //暂停 mMediaController.getTransportControls().pause(); }
参考文章
推荐看参考文2,比较详细
《Android官方文档》
《》