尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

my-tv 直播为何很少彻底卡死:错误感知、重试上限与备用源设计拆解

my-tv 直播为何很少彻底卡死:错误感知、重试上限与备用源设计拆解 my-tv 直播为何很少彻底卡死错误感知、重试上限与备用源设计拆解【免费下载链接】my-tv我的电视 电视直播软件安装即可使用项目地址: https://gitcode.com/GitHub_Trending/my/my-tvmy-tv 是一款装完就能收看的电视直播 App它的播放错误处理与自动恢复机制解决的是直播流随时会断这个现实问题。本文从感知、重试、备用源三个环节拆解它如何快速修复播放故障并说明报错界面为什么只做减法帮你在自己的项目里复刻这条链路。播放突然卡死系统靠什么感知到电视直播的播放对象是网络流断流、超时、解码失败都可能让画面停在黑屏。my-tv 没有自己去轮询播放器状态而是挂在 ExoPlayer 的监听器上等播放器主动抛出异常。感知到错误后代码不做任何恢复动作只往 ViewModel 的 LiveData 里写一个标志位。为什么要绕道 ViewModel监听这个标志位的是 MainFragment.kt。它在创建时给每个频道的 ViewModel 注册了观察者一旦收到信号就决定是重新拉数据还是直接重播tvViewModel.change.observe(viewLifecycleOwner) { _ - if (tvViewModel.change.value ! null) { if (tvViewModel.getTV().pid ! ) { lifecycleScope.launch(Dispatchers.IO) { tvViewModel.let { Request.fetchData(it) } } } else { if (check(tvViewModel)) { (activity as? MainActivity)?.play(tvViewModel) } } } }说白了这里有个坑错误恢复不是就地重连而是换一条路重新取数据。如果频道还能从服务端拿到新地址就走Request.fetchData重新拉如果本来就没有远程请求pid为空就直接play一次。把感知放在播放器、把决策放在 UI 层中间用 LiveData 传话这是 Android 里很典型的单向数据流。同一个错误为什么有的重试有的直接弹提示不是所有失败都值得重试。my-tv 把还能救和救不了分成了两条路判据是错误来源和次数上限逻辑集中在 Request.kt。重试是有硬上限的网络抖动、鉴权过期这类临时错误会触发递归重试但计数器会卡住死循环。每个频道的 ViewModel 里预置了上限var retryTimes 0 var retryMaxTimes 8 var tokenYSPRetryTimes 0 var tokenFHRetryMaxTimes 8请求失败时先判断retryTimes retryMaxTimes成立才自增并重发否则放弃。重试是立即重发靠请求本身的耗时天然拉开间隔避免对服务端造成瞬时压力。注意这里有两套计数器retryTimes管整体请求tokenXxxRetryTimes专门管令牌过期导致的失败。分开计数是为了避免令牌问题和网络问题互相消耗预算。哪些错误直接交给用户有一类错误重试没有意义比如服务端明确返回应版权方要求暂停提供直播信号。这种情况 Request.kt 不会重试而是调用setErrInfo把原文塞进errInfo这个 LiveDataUI 层观察到后用一个 Toast 显示出来。也就是说能自动修的走重试说了也白说的走提示边界划得很清楚。主源挂了备用源什么时候顶上直播流经常有多个 CDN 地址。my-tv 把同一频道的所有可用地址放进一个列表用一个游标标记当前在用哪个这套状态放在 TVViewModel.kt。游标加列表private val _videoUrl MutableLiveDataListString() private val _videoIndex MutableLiveDataInt() fun getVideoUrlCurrent(): String { return _videoUrl.value!![_videoIndex.value!!] }_videoUrl存全部地址_videoIndex指到当前那一个getVideoUrlCurrent()就是取此刻要播的那条。播放器永远只问这一个方法要地址。当新地址请求成功时代码只更新游标再调一次changed()播放器那边就自动取到新地址重播。手动切源除了自动切my-tv 还留了手动入口。MainFragment.kt 的prevSource/nextSource会把游标往前往后拨一格拨到头就绕回另一端然后同样触发changed()。用户觉得当前源卡可以自己切一条系统觉得当前源挂了也能切一条。两条路径最终汇到同一个changed()复用同一套恢复逻辑不用写第二份。错误界面为什么只有一个好的按钮真到了重试也救不回来的地步my-tv 用一个全屏遮罩把错误信息盖在最上层实现是 ErrorFragment.kt继承自 Leanback 的ErrorSupportFragment。界面刻意做得克制一个悲伤云图标、一句说明、一个按钮。按钮文案取自 strings.xml 的dismiss_error值就是好的。为什么不写重试因为走到这里的错误要么是版权停播要么是连续 8 次重试都失败再点重试大概率还是失败徒增挫败感。给一个知道了的出口让用户主动退出错误态比给他一个会再次失败的按钮更体面。点击按钮只会移除这个 Fragment把控制权交还主界面。把这套思路搬进你自己的项目如果你要给自己的播放器或任何依赖外部服务的功能做容错可以直接借鉴这条链路用监听器感知异常、用 LiveData 解耦感知与恢复、给重试设硬上限并区分错误类型、用多源列表加游标做兜底、最后用一个克制的错误出口兜住。my-tv 里 TVViewModel.kt 的状态设计和 Request.kt 的分级重试是把能不能救量化得最清楚的两处值得逐行对照。它的鉴权令牌刷新机制同样是围绕重试预算展开的可以作为下一步深挖的入口。【免费下载链接】my-tv我的电视 电视直播软件安装即可使用项目地址: https://gitcode.com/GitHub_Trending/my/my-tv创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表