跨Activity/Fragment/Adapter传递ExoPlayer的最佳实践咨询
单ExoPlayer实例跨组件共享实现方案
首先明确结论:不要直接用无任何生命周期管控的裸单例托管ExoPlayer,很容易出内存泄漏、状态混乱、后台偷跑的问题。更合适的方案是做生命周期感知的统一播放管理层,配合播放状态全局同步,完全可以满足你的业务需求,具体思路如下:
核心架构设计
- 封装一个
PlaybackManager类,作为唯一持有ExoPlayer实例的管理者,你可以把它做成Application作用域的单例(比如用依赖注入框架限定作用域,或者自己实现带生命周期回调的单例),但绝对不要对外直接暴露持有的ExoPlayer实例,所有操作都通过封装好的接口完成。 PlaybackManager内部只需要维护三个核心状态:当前播放的媒体ID/URL、当前播放位置、播放状态,对外暴露的核心接口包括attachRenderView(PlayerView view)、detachRenderView()、play(String mediaUrl, long startPosition)、getCurrentPosition()、pause()、release()。- 每次调用
attachRenderView时,自动把当前持有的ExoPlayer和新传入的PlayerView绑定,自动解绑之前绑定的旧View,不会重新创建播放器实例,也就实现了无缝续播。
适配你的业务场景的逻辑处理
- 首页RecyclerView滚动播放:监听RecyclerView滚动回调,每次滚动结束后找到第一个完全可见的视频条目,调用
PlaybackManager.play()传入对应视频URL,再把该条目的PlayerView通过attachRenderView绑定即可;滚动过程中直接调用detachRenderView解绑当前视图,播放器自动暂停,不会有多个视频同时播放的问题。 - 点击跳转到详情页续播:跳转前只需要调用
detachRenderView解绑首页的PlayerView,不需要动播放器本身,详情页初始化完成后,把详情页的PlayerView绑定到PlaybackManager,播放器会自动从上次中断的位置继续播放,完全不需要传多余的参数。 - 详情页返回首页续播:详情页销毁前调用
detachRenderView解绑自己的PlayerView,首页回到前台后,找到之前播放的条目,把该条目的PlayerView重新绑定到PlaybackManager就可以直接续播,状态完全同步。 - 多页面播放需求:所有需要播放视频的页面都只和
PlaybackManager交互,不需要各自创建ExoPlayer实例,全程只有一个播放器实例在运行,性能开销最低。
为什么不推荐直接用裸单例
- 裸单例没有生命周期感知能力,很容易出现页面销毁后还持有页面View的引用,导致内存泄漏。
- 没有封装的裸单例如果直接对外暴露ExoPlayer实例,多页面同时操作时很容易出现状态错乱,比如页面切到后台了播放器还在继续播放耗电。
- 没有统一的状态管理,出现播放异常时很难排查问题。
注意事项
- 所有页面的PlayerView绑定和解绑操作要和页面的
onStart/onStop生命周期绑定,不要放到onCreate/onDestroy里,避免页面切换时出现黑屏。 - 应用退到后台时统一调用
PlaybackManager.pause()暂停播放,回到前台后根据场景决定是否恢复播放,避免后台耗电。 - 切换不同的视频源时,
PlaybackManager内部要及时释放之前的媒体源,降低内存占用。
内容的提问来源于stack exchange,提问作者user1695123
相关产品推荐
相关产品推荐

