现在主流的音视频App中,除了当用户正在使用时播映视频或音频,应用回到后台后音视频仍能持续播映的功能也很常见。本文简单介绍下怎么使用Media3库完成在后台播映视频。
官方文档
增加依赖
在app module下的build.gradle中增加代码,如下:
dependencies {
implementation("androidx.media3:media3-ui:1.1.0")
implementation("androidx.media3:media3-session:1.1.0")
implementation("androidx.media3:media3-exoplayer:1.1.0")
}
增加相关权限
在AndroidManifest
中增加前台服务权限,具体如下:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<!--targetSdk34开端需求增加此权限-->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
...
</manifest>
前台服务权限按理来说需求动态请求,但是在测试过程中,发现没有动态请求也能完成在后台播映视频的功能。
完成后台播映
自定义MediaSessionService
自定义ExamplePlaybackService
承继MediaSessionService
,代码如下:
class ExamplePlaybackService : MediaSessionService() {
private var exoPlayer: ExoPlayer? = null
private var mediaSession: MediaSession? = null
override fun onCreate() {
super.onCreate()
// 创立ExoPlayer
exoPlayer = ExoPlayer.Builder(this).build()
// 基于已创立的ExoPlayer创立MediaSession
exoPlayer?.let { mediaSession = MediaSession.Builder(this, it).build() }
}
override fun onDestroy() {
// 开释相关实例
exoPlayer?.stop()
exoPlayer?.release()
exoPlayer = null
mediaSession?.release()
mediaSession = null
super.onDestroy()
}
override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaSession? {
return mediaSession
}
}
在Manifest中注册MediaSessionService
在AndroidManifest
中增加ExamplePlaybackService
,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
...
<application
... >
<!--android 10开端,需求指定foregroundServiceType-->
<service
android:name=".androidapi.media3.ExamplePlaybackService"
android:exported="true"
android:foregroundServiceType="mediaPlayback">
<!--假如需求兼容低版本,需求增加此intent-filter-->
<intent-filter>
<action android:name="androidx.media3.session.MediaSessionService" />
</intent-filter>
</service>
</application>
</manifest>
播映视频
class Media3ExampleActivity : AppCompatActivity() {
private lateinit var binding: LayoutMedia3ExampleActivityBinding
private lateinit var controllerFuture: ListenableFuture<MediaController>
private val mediaController: MediaController?
get() = if (controllerFuture.isDone) controllerFuture.get() else null
private val playerListener = object : Player.Listener {
override fun onIsPlayingChanged(isPlaying: Boolean) {
super.onIsPlayingChanged(isPlaying)
// 播映状况变化回调
}
override fun onPlaybackStateChanged(playbackState: Int) {
super.onPlaybackStateChanged(playbackState)
when (playbackState) {
Player.STATE_IDLE -> {
//播映器中止时的状况
}
Player.STATE_BUFFERING -> {
// 正在缓冲数据
}
Player.STATE_READY -> {
// 能够开端播映
}
Player.STATE_ENDED -> {
// 播映结束
}
}
}
override fun onPlayerError(error: PlaybackException) {
super.onPlayerError(error)
// 获取播映错误信息
}
}
@UnstableApi
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = LayoutMedia3ExampleActivityBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.includeTitle.tvTitle.text = "Media3 Example"
binding.btnPlaySingleVideo.setOnClickListener {
binding.playView.player?.run {
// 中止之前播映的视频
stop()
//设置单个资源
setMediaItem(MediaItem.fromUri("https://minigame.vip/Uploads/images/2021/09/18/1631951892_page_img.mp4"))
// 开端缓冲
prepare()
}
}
binding.btnPlayMultiVideo.setOnClickListener {
binding.playView.player?.run {
// 中止之前播映的视频
stop()
// 设置多个资源,当一个视频播完后自动播映下一个
setMediaItems(arrayListOf(
MediaItem.fromUri("https://minigame.vip/Uploads/images/2021/09/18/1631951892_page_img.mp4"),
MediaItem.fromUri("https://storage.googleapis.com/exoplayer-test-media-1/mp4/dizzy-with-tx3g.mp4")
))
// 开端缓冲
prepare()
}
}
}
private fun initController() {
controllerFuture = MediaController.Builder(this, SessionToken(this, ComponentName(this, ExamplePlaybackService::class.java)))
.buildAsync()
controllerFuture.addListener({
binding.root.post {
mediaController?.let {
binding.playView.player = it.apply {
// 设置播映监听
addListener(playerListener)
// 设置重复形式
// Player.REPEAT_MODE_ALL 无限重复
// Player.REPEAT_MODE_ONE 重复一次
// Player.REPEAT_MODE_OFF 不重复
repeatMode = Player.REPEAT_MODE_ALL
// 设置当缓冲结束后直接播映视频
playWhenReady = true
}
}
}
}, ContextCompat.getMainExecutor(this))
}
override fun onStart() {
super.onStart()
initController()
}
override fun onStop() {
super.onStop()
binding.playView.player = null
MediaController.releaseFuture(controllerFuture)
}
override fun onDestroy() {
super.onDestroy()
// 开释播映器资源
binding.playView.player?.release()
binding.playView.player = null
}
}
作用如图:
能够看到,Media3库内部完成了用于播映的前台服务和通知,不用做额外的操作就能够简单的完成相关功能。
示例
演示代码已在示例Demo中增加。
ExampleDemo github
ExampleDemo gitee