如何让ExoPlayer遇网络问题后从头重试播放?
ExoPlayer网络中断后基于缓存恢复播放的实现方法
问题场景
我实现了一个简易ExoPlayer,加载代码如下:
List<MediaItem> mediaItems = new ArrayList<>(playlist.size()); for (String url : playlist) { mediaItems.add(MediaItem.fromUri(url)); } player.setMediaItems(mediaItems); player.prepare(); player.setRepeatMode(player.REPEAT_MODE_ONE);
该播放器可正常运行,且已实现离线播放功能。目前遇到的问题是:有时出现网络问题会导致播放器停止,能否基于已缓存内容恢复或从头开始播放?
解决方案
1. 捕获播放错误并判断缓存可用性
给ExoPlayer添加监听,捕获网络类播放错误,同时检查当前媒体的缓存状态,若有缓存则尝试恢复播放:
player.addListener(new Player.Listener() { @Override public void onPlayerError(PlaybackException error) { // 识别网络相关错误 if (error.errorCode == PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_FAILED || error.errorCode == PlaybackException.ERROR_CODE_IO_NETWORK_TIMEOUT) { MediaItem currentItem = player.getCurrentMediaItem(); if (currentItem != null && isMediaCached(currentItem)) { // 从头播放缓存内容 player.seekTo(0); player.play(); } } } });
2. 实现缓存状态检查方法
通过你的缓存实例(如SimpleCache)判断媒体是否已缓存:
private boolean isMediaCached(MediaItem mediaItem) { Cache cache = ...; // 替换为你已初始化的缓存实例 CacheKey cacheKey = DefaultCacheKeyFactory.getInstance().buildCacheKey(mediaItem); long cachedLength = cache.getCachedLength(cacheKey); long totalDuration = player.getDuration(); // 只要有缓存内容(或已缓存完整媒体)就返回true return cachedLength > 0 && (totalDuration == C.LENGTH_UNSET || cachedLength >= totalDuration); }
3. 配置自动重试策略
通过自定义LoadControl让播放器在网络波动时自动重试加载,避免直接停止:
DefaultLoadControl loadControl = new DefaultLoadControl.Builder() .setRetryDelayMs(2000) // 每次重试间隔2秒 .setMaxRetryCount(3) // 最多重试3次 .build(); ExoPlayer player = new ExoPlayer.Builder(context) .setLoadControl(loadControl) .build();
4. 强制切换离线播放模式
如果网络长期中断,可以切换到仅使用缓存的数据源,确保播放器仅从缓存读取内容:
private void switchToOfflinePlayback() { Cache cache = ...; // 你的缓存实例 DataSource.Factory offlineDataSource = new CacheDataSource.Factory() .setCache(cache) .setUpstreamDataSourceFactory(new DefaultHttpDataSource.Factory()) .setFlags(CacheDataSource.FLAG_BLOCK_ON_CACHE); // 强制从缓存读取 ProgressiveMediaSource offlineSource = new ProgressiveMediaSource.Factory(offlineDataSource) .createMediaSource(player.getCurrentMediaItem()); player.setMediaSource(offlineSource); player.prepare(); player.play(); }
内容的提问来源于stack exchange,提问作者Rodrigo
相关产品推荐
相关产品推荐

