Android官方组件 MediaBrowser 分析

MediaBrowser 是官方推出的基于Android四大组件之一 Service 的新框架,使用起来很方便。

如何连接:

	//连接到远端Service
    public boolean registerConnection(@NonNull Context mContext, @NonNull Class<? extends Service> clazz, @Nullable Bundle mBundle) {
        try {
            if (mMediaBrowser == null) {
                mApplicationContext = new WeakReference<>(mContext.getApplicationContext());
                mMediaBrowser = new MediaBrowserCompat(mContext, new ComponentName(mContext, clazz), mConnectionCallback, mBundle);
                mMediaBrowser.connect();
            } else if (mMediaBrowser.isConnected()) {
                mRepeatMode.setValue(getPlaybackMode());
                ARouter.getInstance().build(RouterPath.Router_Main)
                        .addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT).navigation();
            } else if (!mMediaBrowser.isConnected()) {
                mMediaBrowser.disconnect();
                mApplicationContext = new WeakReference<>(mContext.getApplicationContext());
                mMediaBrowser.connect();
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

	//连接后的回调,不管成功还是失败都会回调这里
    private final MediaBrowserCompat.ConnectionCallback mConnectionCallback = new MediaBrowserCompat.ConnectionCallback() {
        @Override
        public void onConnected() {
            super.onConnected();
            try {
                MediaSessionCompat.Token token = mMediaBrowser.getSessionToken();
                mMediaController = new MediaControllerCompat(mApplicationContext.get(), token);
                mMediaController.registerCallback(mCallback, mHandler);
                mTransportControls = mMediaController.getTransportControls();	//连接成功之后才可以获取媒体控制对象(TransportControls)和媒体浏览控制对象(MediaController)
                initialized = true;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onConnectionSuspended() {
            super.onConnectionSuspended();
            isPlaying = false;
            try {
                reconnet();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onConnectionFailed() {
            super.onConnectionFailed();
        }
    };


    @Nullable
    public MediaControllerCompat.TransportControls getTransportControls() {
        if (mTransportControls == null) {
            Log.e(TAG, "service has not been launched, call this method again after called registerConnection(...)");
        }
        return mTransportControls;
    }

    @Nullable
    public MediaControllerCompat getMediaController() {
        if (mMediaController == null) {
            Log.e(TAG, "service has not been launched, call this method again after called registerConnection(...)");
        }
        return mMediaController;
    }

首先看代码:Service层

//用于UI层向Service层发送 获取数据的请求,然后异步返回数据
fun onLoadChildren(
        parentId: String, //对应UI层registerSubscribeCallback中的parentId
        result: Result<MutableList<MediaBrowserCompat.MediaItem>>,//异步返回数据的对象
        options: Bundle
)

//在UI层首次连接时调用,通常在这里做权限校验
fun onGetRoot(
        clientPackageName: String,
        clientUid: Int,
        rootHints: Bundle?
): BrowserRoot? {
    Log.d(tag, "Connected from pkg:$clientPackageName uid:$clientUid")
    return BrowserRoot(browserRoot, rootHints)
}

//UI层做搜索时使用,不过我在使用这个方法作为搜索的时候,会有内存泄漏的问题,而且一直无法解决,所以我把这个方法弃用了
fun onSearch(
        query: String,
        extras: Bundle?,
        result: Result<MutableList<MediaBrowserCompat.MediaItem>>
)

【注意】:在使用Result<*>对象的时候,如果此次数据获取是耗时操作,那么需要直接调用result.detach() 来将此条消息从当前线程中释放,然后为下面调用result.sendResult()提供方便;

UI层:

/*
	要实现对后台服务进行控制,我们需要实现
	android.support.v4.media.session.MediaControllerCompat.Callback
	android.support.v4.media.MediaBrowserCompat.ConnectionCallback
	前者用于接收控制结束后的回调,后者用于连接MediaBrowserService
*/
public boolean registerSubscribeCallback(@NonNull String parentId, @NonNull MediaBrowserCompat.SubscriptionCallback callback, @NonNull Bundle options) {
    try {
    	//MediaBrowserCompat 对象会持有callback对象,如果不手动解除注册,会产生内存泄漏问题。
        mMediaBrowser.unsubscribe(parentId);
        mMediaBrowser.subscribe(parentId, options, callback);
    } catch (Exception e) {
        e.printStackTrace();
        return false;
    }
    return true;
}

一般我们针对MediaSession进行适配的时候,需要几个地方需要注意:

MediaMetadataCompat:
  • MediaMetadataCompat.METADATA_KEY_DURATION: 对应的是当前正在播放的媒体时长
  • MediaMetadataCompat.METADATA_KEY_ALBUM_ART: 对应的是原生锁屏的封面,传入bitmap会直接应用到锁屏封面上,不过一些魔改的rom不支持
构造方法:
MediaMetadataCompat.Builder()
   .putString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID, description.mediaId)
    .putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, title as String?)
    .putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_SUBTITLE, subTitle as String?)
    .putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_DESCRIPTION,descriptionStr)
    .putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON_URI, iconUri)
    .putString(MediaMetadataCompat.METADATA_KEY_TITLE, title)
    .putString(MediaMetadataCompat.METADATA_KEY_ARTIST, artist)
    .putString(MediaMetadataCompat.METADATA_KEY_ALBUM, album)
    .putString(MediaMetadataCompat.METADATA_KEY_ALBUM_ARTIST, artist)
    .putString(MediaMetadataCompat.METADATA_KEY_AUTHOR, artist)
    .putLong(MediaMetadataCompat.METADATA_KEY_DURATION, mDuration)
    .putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, mLargeIcon)
    .build()
PlaybackStateCompat:
  • 在构造这个对象的时候,其中的setState(@State int state, long position, float playbackSpeed)方法, state表示当前播放的状态,包含很多种(正在播放,缓冲,暂停,跳转下一首,跳转前一首等),position表示当前播放的进度,当传入position后,而且state的状态为playing,那么状态栏的进度会自动进行,如果state的状态为pause,那么状态栏的进度也会暂停。playbackspeed则是表示状态栏进度条的进行速度,一般传入1,表示正常速度,传入2f表示2倍速,以此类推
构造方法:
PlaybackStateCompat.Builder().setActions(mMediaSessionActions)
    .setState(state, mCurrentPosition, 1.0f)
    .build()

除此以外,还有很多额外的扩展功能:比如可以修改播放模式,自定义操作,接收媒体按钮事件,获取正在播放的队列。

现在很多蓝牙设备,车载设备都是基于这个服务的,所以我们只要针对这个服务把适配做好了,那么在车载设备上也有很好的体验。

比如适配好了当前播放的队列之后,就可以在车载设备上看到歌曲列表,就不用操作手机来切换选择歌曲等等。

补充一句:里面的很多对象都是基于内置的对象,比如MediaItem,QueueItem这些,需要我们专门写适配器进行适配,这是比较麻烦的地方,还有一些内存泄漏的问题,也需要去解决。

写篇博文,记录一下

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
MediaBrowserAndroid中的一个类,用于在车机系统中浏览和播放媒体内容。它提供了一种与车机系统中的媒体浏览服务进行交互的方式。通过MediaBrowser,应用可以获取车机系统中的媒体内容,并控制媒体的播放。 以下是使用MediaBrowser的示例代码: ```java // 创建一个MediaBrowser连接 MediaBrowser mediaBrowser = new MediaBrowser(context, new ComponentName(context, MediaPlaybackService.class), connectionCallbacks, null); // 连接到媒体浏览服务 mediaBrowser.connect(); // 在连接成功后,获取媒体浏览根节点 MediaBrowserCompat.MediaItem rootItem = mediaBrowser.getRoot(); // 获取媒体浏览根节点下的子节点 List<MediaBrowserCompat.MediaItem> mediaItems = rootItem.getChildren(); // 遍历子节点,获取媒体信息 for (MediaBrowserCompat.MediaItem mediaItem : mediaItems) { String title = mediaItem.getDescription().getTitle().toString(); String artist = mediaItem.getDescription().getSubtitle().toString(); String mediaId = mediaItem.getMediaId(); // 处理媒体信息 } // 控制媒体的播放 mediaBrowser.getTransportControls().play(); mediaBrowser.getTransportControls().pause(); mediaBrowser.getTransportControls().skipToNext(); mediaBrowser.getTransportControls().skipToPrevious(); // 断开与媒体浏览服务的连接 mediaBrowser.disconnect(); ``` 通过使用MediaBrowser,应用可以与车机系统中的媒体浏览服务进行交互,获取媒体内容并控制媒体的播放。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值