列表中实现VideoView播放.m3u8视频时滚动触发MediaPlayer异常求助
解决VideoView加载.m3u8滚动列表时的FileNotFoundException问题
我之前在开发列表视频播放功能时也踩过这个坑,咱们来拆解一下问题和解决办法:
为什么会出现这个错误?
Android原生的VideoView底层依赖的MediaPlayer对HLS(.m3u8)这种流媒体格式的支持非常有限,尤其是在旧版本系统上。另外当列表滚动触发视图复用时,旧的VideoView实例可能没有正确释放资源,导致新的数据源设置时出现ContentResolver无法识别HTTPS流媒体路径的错误——毕竟ContentResolver主要是用来处理本地内容或系统内置内容提供者的,不是为网络流媒体设计的。
解决方案推荐
1. 替换为ExoPlayer(最靠谱的方案)
Google官方推荐用ExoPlayer来处理各种流媒体格式,包括HLS,它的兼容性和稳定性都比原生VideoView好太多。
- 首先添加依赖(在app的build.gradle里):
implementation "com.google.android.exoplayer:exoplayer-core:2.X.X" implementation "com.google.android.exoplayer:exoplayer-hls:2.X.X" // HLS支持模块
(注:把2.X.X替换成最新版本号)
- 布局里用
PlayerView替代VideoView:
<com.google.android.exoplayer2.ui.PlayerView android:id="@+id/player_view" android:layout_width="match_parent" android:layout_height="wrap_content"/>
- 在Adapter的ViewHolder里初始化和管理ExoPlayer:
public class VideoViewHolder extends RecyclerView.ViewHolder { private PlayerView playerView; private SimpleExoPlayer player; public VideoViewHolder(View itemView) { super(itemView); playerView = itemView.findViewById(R.id.player_view); } public void bind(String videoUrl) { // 初始化ExoPlayer if (player == null) { player = new SimpleExoPlayer.Builder(itemView.getContext()).build(); playerView.setPlayer(player); } // 准备HLS媒体源 MediaItem mediaItem = MediaItem.fromUri(videoUrl); player.setMediaItem(mediaItem); player.prepare(); // 可选:自动播放 // player.play(); } // 回收时释放资源 public void release() { if (player != null) { player.release(); player = null; } } }
- 在Adapter里重写视图回收方法:
@Override public void onViewRecycled(@NonNull VideoViewHolder holder) { super.onViewRecycled(holder); holder.release(); }
2. 如果你非要用VideoView(不推荐)
如果因为某些原因必须用VideoView,那要做好资源释放和格式兼容处理:
- 首先,在Android 4.1+系统上,原生
MediaPlayer有限支持HLS,但需要确保视频的编码格式是系统支持的。 - 然后,在列表视图回收时必须彻底释放
VideoView的资源:
@Override public void onViewRecycled(@NonNull VideoViewHolder holder) { super.onViewRecycled(holder); holder.videoView.stopPlayback(); holder.videoView.setVideoURI(null); // 清空数据源 }
- 另外,加载视频时可以尝试用
Uri.parse()来处理路径,而不是直接传字符串:
holder.videoView.setVideoURI(Uri.parse(videoUrl));
3. 基础配置检查
- 确保manifest里已经申请了网络权限:
<uses-permission android:name="android.permission.INTERNET"/>
- 如果是Android 9(API 28)及以上,检查是否允许明文网络(如果你的m3u8是HTTPS的话其实不需要,但如果是HTTP的话需要):
在manifest的application标签里添加:
android:usesCleartextTraffic="true"
这样处理后,滚动列表时的错误应该就能解决了,优先推荐用ExoPlayer,毕竟原生VideoView在流媒体场景下的局限性太大了。
内容的提问来源于stack exchange,提问作者Vikramsinh Gaikwad
相关产品推荐
相关产品推荐

