Android TV端YoutubePlayer onError方法未触发问题求助
Android TV YoutubePlayer 网络错误监听失效的解决办法
YoutubePlayer自带的onError回调并不是万能的,尤其是在Android TV场景下,很多网络断开的情况不会触发这个回调——比如视频加载前就断网、播放中网络波动但播放器内部没抛出错误。下面给你几个实用的解决思路:
1. 主动监听系统网络状态变化
播放器自身的错误回调有局限性,必须主动监听系统网络状态才能覆盖所有断网场景:
- 先在Manifest中添加权限:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.INTERNET" />
- 使用
ConnectivityManager.NetworkCallback实时监听网络连接,断网时直接触发弹窗:
private lateinit var networkCallback: ConnectivityManager.NetworkCallback private fun registerNetworkListener() { val connectivityManager = requireContext().getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager networkCallback = object : ConnectivityManager.NetworkCallback() { override fun onLost(network: Network) { super.onLost(network) requireActivity().runOnUiThread { showNetworkErrorDialog() } } override fun onAvailable(network: Network) { super.onAvailable(network) initializedYouTubePlayer?.let { player -> if (isEulaAccepted) { player.loadVideo( glance.peek.videoPeek.video.youtubeVideo.videoId, videoStartTime.toFloat() ) } } } } val networkRequest = NetworkRequest.Builder() .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) .build() connectivityManager.registerNetworkCallback(networkRequest, networkCallback) } // 在Fragment销毁时注销监听,避免内存泄漏 override fun onDestroyView() { super.onDestroyView() val connectivityManager = requireContext().getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager connectivityManager.unregisterNetworkCallback(networkCallback) } private fun showNetworkErrorDialog() { AlertDialog.Builder(requireContext()) .setTitle("网络错误") .setMessage("当前网络不可用,请检查网络连接") .setPositiveButton("确定") { dialog, _ -> dialog.dismiss() } .show() }
2. 结合播放器缓冲状态判断网络异常
播放中突然断网可能只会触发BUFFERING状态而不会抛出错误,这时候可以通过缓冲时长结合网络状态判断:
private var bufferingStartTime: Long = 0 private val bufferingHandler = Handler(Looper.getMainLooper()) override fun onStateChange(youTubePlayer: YouTubePlayer, state: PlayerConstants.PlayerState) { handleVideoStateChange(state) when (state) { PlayerConstants.PlayerState.BUFFERING -> { bufferingStartTime = System.currentTimeMillis() bufferingHandler.postDelayed({ val isBufferingTimeout = System.currentTimeMillis() - bufferingStartTime > 5000 if (isBufferingTimeout && !isNetworkAvailable(requireContext())) { showNetworkErrorDialog() } }, 5000) } else -> { bufferingHandler.removeCallbacksAndMessages(null) } } } // 辅助方法:检查当前网络是否可用 private fun isNetworkAvailable(context: Context): Boolean { val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager val network = connectivityManager.activeNetwork ?: return false val capabilities = connectivityManager.getNetworkCapabilities(network) ?: return false return capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) }
3. 完善播放器错误回调的处理
确认播放器版本是否支持全量错误回调,同时细化onError的分支处理:
override fun onError(youTubePlayer: YouTubePlayer, error: PlayerConstants.PlayerError) { super.onError(youTubePlayer, error) Timber.i("Youtube错误类型: ${error.name}") when(error) { PlayerConstants.PlayerError.NETWORK_ERROR, PlayerConstants.PlayerError.NO_CONNECTION -> { showNetworkErrorDialog() } else -> { setErrorCodes("Youtube error:${error.name}") } } }
把以上三种方式结合使用,就能覆盖绝大多数网络异常场景了。
内容的提问来源于stack exchange,提问作者Parag Rane
相关产品推荐
相关产品推荐

