ExoPlayer 2.18.1问题:切换页面后视频后台播放如何解决(Kotlin)
解决Fragment Adapter中ExoPlayer后台播放问题
要解决切换页面后视频继续播放的问题,核心是将ExoPlayer的生命周期与Fragment的生命周期绑定,在Fragment不可见时暂停并释放播放器资源。以下是具体的Kotlin实现方案:
1. 封装ViewHolder的播放器管理
在Adapter的ViewHolder中单独维护每个Item的ExoPlayer实例,并提供暂停、释放的方法,同时避免ViewHolder复用时的资源泄漏:
class VideoViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { private var player: ExoPlayer? = null private val playerView = itemView.findViewById<PlayerView>(R.id.player_view) fun bind(videoUrl: String) { // 初始化ExoPlayer player = ExoPlayer.Builder(itemView.context).build().apply { setMediaItem(MediaItem.fromUri(videoUrl)) prepare() playWhenReady = false // 默认不自动播放,按需调整 playerView.player = this } } // 暂停播放 fun pausePlayback() { player?.playWhenReady = false } // 释放播放器资源 fun releasePlayer() { player?.release() player = null playerView.player = null } }
2. 在Adapter中统一管理所有活跃播放器
在Adapter里维护活跃播放器列表,提供批量暂停、释放的方法,同时处理ViewHolder回收时的资源清理:
class VideoAdapter(private val videoUrls: List<String>) : RecyclerView.Adapter<VideoViewHolder>() { private val activePlayers = mutableListOf<ExoPlayer>() override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VideoViewHolder { val view = LayoutInflater.from(parent.context) .inflate(R.layout.item_video, parent, false) return VideoViewHolder(view) } override fun onBindViewHolder(holder: VideoViewHolder, position: Int) { holder.bind(videoUrls[position]) holder.player?.let { if (!activePlayers.contains(it)) { activePlayers.add(it) } } } // 回收ViewHolder时释放对应播放器 override fun onViewRecycled(holder: VideoViewHolder) { super.onViewRecycled(holder) holder.pausePlayback() holder.releasePlayer() activePlayers.remove(holder.player) } // 批量暂停所有播放器 fun pauseAllPlayers() { activePlayers.forEach { it.playWhenReady = false } } // 批量释放所有播放器资源 fun releaseAllPlayers() { activePlayers.forEach { it.release() } activePlayers.clear() } }
3. 绑定Fragment的生命周期回调
在承载RecyclerView的Fragment中,利用生命周期方法通知Adapter处理播放器:
class VideoListFragment : Fragment() { private lateinit var videoAdapter: VideoAdapter override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { val view = inflater.inflate(R.layout.fragment_video_list, container, false) val recyclerView = view.findViewById<RecyclerView>(R.id.video_recycler) videoAdapter = VideoAdapter(getVideoUrlList()) recyclerView.apply { adapter = videoAdapter layoutManager = LinearLayoutManager(context) } return view } // Fragment暂停时,暂停所有视频播放 override fun onPause() { super.onPause() videoAdapter.pauseAllPlayers() } // Fragment停止时,释放所有播放器资源 override fun onStop() { super.onStop() videoAdapter.releaseAllPlayers() } private fun getVideoUrlList(): List<String> { // 替换为你的视频URL列表 return listOf( "https://example.com/video1.mp4", "https://example.com/video2.mp4" ) } }
关键说明
- 生命周期绑定:Fragment的
onPause和onStop会在切换到其他页面时触发,此时调用Adapter的方法可以确保所有播放器暂停并释放资源,彻底停止后台播放。 - 资源回收:在ViewHolder被回收时释放播放器,避免RecyclerView复用导致的内存泄漏。
- 按需调整:如果需要Fragment回到前台时恢复播放,可以在
onResume中重新初始化播放器(需根据业务逻辑判断是否自动恢复)。
内容的提问来源于stack exchange,提问作者Arun.E
相关产品推荐
相关产品推荐

