一、概念
二、提供服务
2.1 创建 Service
|
MediaSession.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 注册 Service
<service
android:name=".PlayerService"
android:foregroundServiceType="mediaPlayback"
android:exported="true">
<intent-filter>
<action android:name="androidx.media3.session.MediaSessionService"/>
<action android:name="android.media.browse.MediaBrowserService"/>
</intent-filter>
</service>
2.3 配置权限
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
三、使用
3.1 连接服务
class ControllerActivity : AppCompatActivity() {
private lateinit var controllerFuture: ListenableFuture<MediaController>
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) {
//连接失败
}
// 如果在界面以外的其他进程中运行服务,使用 ContextCompat.getMainExecutor() 而不是 MoreExecutors.directExecutor()。
}, mainExecutor )
}
}
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): ListenableFuture<SessionResult> {
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) {}
}
}
4029

被折叠的 条评论
为什么被折叠?



