前言

Android 5.0开始引入的媒体应用框架,分为媒体控制器MediaController(用于界面UI)和媒体会话MediaSession(用于播放器Player)。MediaSession框架,使用一套接口,减少了很多流程的繁琐和service的通信等,实现多个设备或者UI的统一调用,其代码可读性、结构耦合度(解耦UI和播放器:MediaPlayer、ExoPlayer等)方面都控制得非常好。

MediaSession主要应用于播放音频或视频的多媒体应用中。

本文简单的介绍一下MediaSession框架的使用。

记录于此,方便自己查阅。

正文

MediaSession框架主要如下几个类:

  1. MediaBrowser

    媒体浏览器,用来连接媒体服务MediaBrowserService和订阅数据,在注册的回调接口中我们就可以获取到Service的连接状态、获取音乐数据。一般在客户端中创建。

  2. MediaBrowserService

    媒体服务,它有两个关键的回调函数onGetRoot()和onLoadChildren()

    onGetRoot():控制客户端媒体浏览器的连接请求,返回值中决定是否允许连接

    onLoadChildren():媒体浏览器向服务器发送数据订阅请求时会被调用,一般在这里执行异步获取数据的操作,然后在将数据发送回媒体浏览器注册的接口中。

  3. MediaSession

    媒体会话,受控端,通过设置MediaSessionCompat.Callback回调来接收MediaController发送的指令,收到指令后会触发Callback中的回调方法,比如播放暂停等。

    Session一般在MediaBrowserService.onCreate方法中创建,最后需调用setSessionToken方法设置用于和控制器配对的令牌并通知浏览器连接服务成功。

  4. MediaController

    媒体控制器,在客户端中工作,通过控制器向媒体服务器发送指令,然后通过MediaControllerCompat.Callback设置回调函数来接受服务端的状态。

    MediaController创建时需要受控端的配对令牌,因此需要在浏览器连接成功后才进行MediaController的创建。

  5. PlaybackState

    封装了各种播放状态。

  6. 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,比较详细

  1. 《Android官方文档》

  2. Android车载多媒体开发MediaSession框架理解(建议收藏)

相关文章

暂无评论

none
暂无评论...