)
一、概念二、提供服务2.1 创建 ServiceMediaSession.Callback可重写的回调onAddMediaItems()onConnect()onCustomCommand()控制器发送过来的自定义命令。onDisconnected()onMediaButtonEvent()onPlaybackResumption()onPlayerInteractionFinished()onPostConnect()onSetMediaItems()onSetRating()class PlayerService : MediaSessionService() { private var mediaSession: MediaSession? null private val sessionCallback by lazy { //重写需要的回调来响应外部控制器发送的命令 object : MediaSession.Callback {} } override fun onCreate() { super.onCreate() //不建议在这里设置播放器监听Player.Listener //因为可能有很多MediaController连接过来 //所以应该放在初始化MediaController的时候定制各自的监听 val player ExoPlayer.Builder(this).build() mediaSession MediaSession.Builder(this, player) .setCallback(sessionCallback) //设置会话监听 .build() } // 供外部控制器访问 override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaSession? { return mediaSession } // 用户关闭应用时停止服务 override fun onTaskRemoved(rootIntent: Intent?) { pauseAllPlayersAndStopSelf() } // 释放资源 override fun onDestroy() { super.onDestroy() mediaSession?.run { player.release() release() mediaSession null } } }2.2 注册 Serviceservice android:name.PlayerService android:foregroundServiceTypemediaPlayback android:exportedtrue intent-filter action android:nameandroidx.media3.session.MediaSessionService/ action android:nameandroid.media.browse.MediaBrowserService/ /intent-filter /service2.3 配置权限uses-permission android:nameandroid.permission.FOREGROUND_SERVICE / uses-permission android:nameandroid.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK /三、使用3.1 连接服务class ControllerActivity : AppCompatActivity() { private lateinit var controllerFuture: ListenableFutureMediaController private var mediaController: MediaController? null private val controllerListener by lazy { //重写需要的控制器监听 object : MediaController.Listener {} } private val playerListener by lazy { //重写需要的播放器监听 object : Player.Listener {} } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_controller) startForegroundService(Intent(this, PlayerService::class.java)) connectToSession() } private fun connectToSession() { // 指定要连接的Service val sessionToken SessionToken(this, ComponentName(this, PlayerService::class.java)) // 异步构建 MediaController controllerFuture MediaController.Builder(this, sessionToken) .setListener(controllerListener) //控制器监听 .buildAsync() // 连接成功的回调 controllerFuture.addListener({ try { mediaController controllerFuture.get().apply{ // 进行初始化配置用起来同ExoPlayer的Player一样 addListener(playerListener) //播放器监听 repeatMode Player.REPEAT_MODE_ONE prepare() } } catch (e: Exception) { //连接失败 } }, mainExecutor ) } override fun onDestroy() { //释放资源 MediaController.releaseFuture(controllerFuture) } }3.1.1 优化mediaController 不一定什么时候初始化完毕若是需要界面一打开就要播放的情况可以对成员变量使用Delegates在不为默认值null时撤掉遮挡UI允许用户操作。private var mediaController: MediaController? by Delegates.observable(null) { property, oldValue, newValue - //此时 mediaController 可用关闭初始化遮挡界面允许用户操作 }3.2 设置控制器监听连接监听MediaController.Listener控制器可以设置的监听onAvailableSessionCommandsChanged()onCustomCommand()会话发送过来的自定义命令。onCustomLayoutChanged()onDisconnected()onError()onExtrasChanged()onMediaButtonPreferencesChanged()onSessionActivityChanged()onSetCustomLayout()private val controllerListener by lazy { object : MediaController.Listener { // 当会话发送自定义命令时 override fun onCustomCommand(controller: MediaController, command: SessionCommand, args: Bundle): ListenableFutureSessionResult { return when (command.customAction) { // FAVORITE - { // val isFavorite args.getBoolean(isFavorite, false) // handleFavoriteCommand(isFavorite) // Futures.immediateFuture(SessionResult(SessionResult.RESULT_SUCCESS)) // } else - super.onCustomCommand(controller, command, args) } } // 当控制器与会话断开连接时 override fun onDisconnected(controller: MediaController) { super.onDisconnected(controller) } } }3.3 设置播放器监听同 ExoPlayer都是 Player.Listener。private val playerListener by lazy { object : Player.Listener { //播放器状态 override fun onPlaybackStateChanged(playbackState: Int) { when (playbackState) { //空闲 Player.STATE_IDLE - {} //缓冲中 Player.STATE_BUFFERING - {} //就绪 Player.STATE_READY - {} //播放完 Player.STATE_ENDED - {} } } //播放列表 override fun onTimelineChanged(timeline: Timeline, reason: Int) { when(reason) { //播放列表发生变化时 Player.TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED - {} //媒体源更新而发生变化 Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE - {} } } //播放错误 override fun onPlayerError(error: PlaybackException) { when (error.cause) { //http错误 is HttpDataSource.HttpDataSourceException - {} else - {} } when (error.errorCode) { //网络错误 PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_FAILED - {} //解码错误 PlaybackException.ERROR_CODE_DECODING_FAILED - {} else - {} } } //播放暂停按钮 override fun onIsPlayingChanged(isPlaying: Boolean) {} //切歌 override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) {} } }