当前位置:   article > 正文

Android Media3(二) — 在后台播放视频_mediacontroller is available here with controllerf

mediacontroller is available here with controllerfuture.get()

目前主流的音视频App中,除了当用户正在使用时播放视频或音频,应用回到后台后音视频仍能继续播放的功能也很常见。本文简单介绍下如何使用Media3库实现在后台播放视频。

官方文档

添加依赖

在app module下的build.gradle中添加代码,如下:
 

  1. dependencies {
  2. implementation("androidx.media3:media3-ui:1.1.0")
  3. implementation("androidx.media3:media3-session:1.1.0")
  4. implementation("androidx.media3:media3-exoplayer:1.1.0")
  5. }

添加相关权限

AndroidManifest中添加前台服务权限,具体如下:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android">
  3. <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
  4. <!--targetSdk34开始需要添加此权限-->
  5. <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
  6. ...
  7. </manifest>

前台服务权限按理来说需要动态申请,但是在测试过程中,发现没有动态申请也能实现在后台播放视频的功能。

实现后台播放

自定义MediaSessionService

自定义ExamplePlaybackService继承MediaSessionService,代码如下:

  1. class ExamplePlaybackService : MediaSessionService() {
  2. private var exoPlayer: ExoPlayer? = null
  3. private var mediaSession: MediaSession? = null
  4. override fun onCreate() {
  5. super.onCreate()
  6. // 创建ExoPlayer
  7. exoPlayer = ExoPlayer.Builder(this).build()
  8. // 基于已创建的ExoPlayer创建MediaSession
  9. exoPlayer?.let { mediaSession = MediaSession.Builder(this, it).build() }
  10. }
  11. override fun onDestroy() {
  12. // 释放相关实例
  13. exoPlayer?.stop()
  14. exoPlayer?.release()
  15. exoPlayer = null
  16. mediaSession?.release()
  17. mediaSession = null
  18. super.onDestroy()
  19. }
  20. override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaSession? {
  21. return mediaSession
  22. }
  23. }

在Manifest中注册MediaSessionService

AndroidManifest中添加ExamplePlaybackService,代码如下:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android">
  3. ...
  4. <application
  5. ... >
  6. <!--android 10开始,需要指定foregroundServiceType-->
  7. <service
  8. android:name=".androidapi.media3.ExamplePlaybackService"
  9. android:exported="true"
  10. android:foregroundServiceType="mediaPlayback">
  11. <!--如果需要兼容低版本,需要添加此intent-filter-->
  12. <intent-filter>
  13. <action android:name="androidx.media3.session.MediaSessionService" />
  14. </intent-filter>
  15. </service>
  16. </application>
  17. </manifest>

播放视频

  1. class Media3ExampleActivity : AppCompatActivity() {
  2. private lateinit var binding: LayoutMedia3ExampleActivityBinding
  3. private lateinit var controllerFuture: ListenableFuture<MediaController>
  4. private val mediaController: MediaController?
  5. get() = if (controllerFuture.isDone) controllerFuture.get() else null
  6. private val playerListener = object : Player.Listener {
  7. override fun onIsPlayingChanged(isPlaying: Boolean) {
  8. super.onIsPlayingChanged(isPlaying)
  9. // 播放状态变化回调
  10. }
  11. override fun onPlaybackStateChanged(playbackState: Int) {
  12. super.onPlaybackStateChanged(playbackState)
  13. when (playbackState) {
  14. Player.STATE_IDLE -> {
  15. //播放器停止时的状态
  16. }
  17. Player.STATE_BUFFERING -> {
  18. // 正在缓冲数据
  19. }
  20. Player.STATE_READY -> {
  21. // 可以开始播放
  22. }
  23. Player.STATE_ENDED -> {
  24. // 播放结束
  25. }
  26. }
  27. }
  28. override fun onPlayerError(error: PlaybackException) {
  29. super.onPlayerError(error)
  30. // 获取播放错误信息
  31. }
  32. }
  33. @UnstableApi
  34. override fun onCreate(savedInstanceState: Bundle?) {
  35. super.onCreate(savedInstanceState)
  36. binding = LayoutMedia3ExampleActivityBinding.inflate(layoutInflater)
  37. setContentView(binding.root)
  38. binding.includeTitle.tvTitle.text = "Media3 Example"
  39. binding.btnPlaySingleVideo.setOnClickListener {
  40. binding.playView.player?.run {
  41. // 停止之前播放的视频
  42. stop()
  43. //设置单个资源
  44. setMediaItem(MediaItem.fromUri("https://minigame.vip/Uploads/images/2021/09/18/1631951892_page_img.mp4"))
  45. // 开始缓冲
  46. prepare()
  47. }
  48. }
  49. binding.btnPlayMultiVideo.setOnClickListener {
  50. binding.playView.player?.run {
  51. // 停止之前播放的视频
  52. stop()
  53. // 设置多个资源,当一个视频播完后自动播放下一个
  54. setMediaItems(arrayListOf(
  55. MediaItem.fromUri("https://minigame.vip/Uploads/images/2021/09/18/1631951892_page_img.mp4"),
  56. MediaItem.fromUri("https://storage.googleapis.com/exoplayer-test-media-1/mp4/dizzy-with-tx3g.mp4")
  57. ))
  58. // 开始缓冲
  59. prepare()
  60. }
  61. }
  62. }
  63. private fun initController() {
  64. controllerFuture = MediaController.Builder(this, SessionToken(this, ComponentName(this, ExamplePlaybackService::class.java)))
  65. .buildAsync()
  66. controllerFuture.addListener({
  67. binding.root.post {
  68. mediaController?.let {
  69. binding.playView.player = it.apply {
  70. // 设置播放监听
  71. addListener(playerListener)
  72. // 设置重复模式
  73. // Player.REPEAT_MODE_ALL 无限重复
  74. // Player.REPEAT_MODE_ONE 重复一次
  75. // Player.REPEAT_MODE_OFF 不重复
  76. repeatMode = Player.REPEAT_MODE_ALL
  77. // 设置当缓冲完毕后直接播放视频
  78. playWhenReady = true
  79. }
  80. }
  81. }
  82. }, ContextCompat.getMainExecutor(this))
  83. }
  84. override fun onStart() {
  85. super.onStart()
  86. initController()
  87. }
  88. override fun onStop() {
  89. super.onStop()
  90. binding.playView.player = null
  91. MediaController.releaseFuture(controllerFuture)
  92. }
  93. override fun onDestroy() {
  94. super.onDestroy()
  95. // 释放播放器资源
  96. binding.playView.player?.release()
  97. binding.playView.player = null
  98. }
  99. }

效果如图:

可以看到,Media3库内部实现了用于播放的前台服务和通知,不用做额外的操作就可以简单的实现相关功能。

示例

演示代码已在示例Demo中添加。

ExampleDemo github

ExampleDemo gitee

原文 Android Media3(二) - 在后台播放视频

★文末名片可以免费领取音视频开发学习资料,内容包括(FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)以及音视频学习路线图等等。

见下方!↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

 

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号