You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 04:22:25