Flutter登录页背景视频播放报错:ExoPlaybackException: Source error
问题:Flutter中使用VideoPlayerController.asset加载本地视频失败
开发带背景视频的登录页时,通过VideoPlayerController.asset初始化、加载并播放视频时出现播放错误,错误日志如下:
I/ExoPlayerImpl( 1409): Release 3fa0f6d [ExoPlayerLib/2.18.1] [emu64x, sdk_gphone64_x86_64, Google, 33] [goog.exo.core, goog.exo.exoplayer, goog.exo.decoder, goog.exo.datasource] I/ExoPlayerImpl( 1409): Init 2f7c84d [ExoPlayerLib/2.18.1] [emu64x, sdk_gphone64_x86_64, Google, 33] D/EGL_emulation( 1409): app_time_stats: avg=8839.84ms min=8839.84ms max=8839.84ms count=1 E/ExoPlayerImplInternal( 1409): Playback error E/ExoPlayerImplInternal( 1409): com.google.android.exoplayer2.ExoPlaybackException: Source error E/ExoPlayerImplInternal( 1409): at com.google.android.exoplayer2.ExoPlayerImplInternal.handleIoException(ExoPlayerImplInternal.java:632) E/ExoPlayerImplInternal( 1409): at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:604) E/ExoPlayerImplInternal( 1409): at android.os.Handler.dispatchMessage(Handler.java:102) E/ExoPlayerImplInternal( 1409): at android.os.Looper.loopOnce(Looper.java:201) E/ExoPlayerImplInternal( 1409): at android.os.Looper.loop(Looper.java:288) E/ExoPlayerImplInternal( 1409): at android.os.HandlerThread.run(HandlerThread.java:67) E/ExoPlayerImplInternal( 1409): Caused by: com.google.android.exoplayer2.upstream.AssetDataSource$AssetDataSourceException: java.io.FileNotFoundException: flutter_assets/violet2.mp4 E/ExoPlayerImplInternal( 1409): at com.google.android.exoplayer2.upstream.AssetDataSource.open(AssetDataSource.java:110) E/ExoPlayerImplInternal( 1409): at com.google.android.exoplayer2.upstream.DefaultDataSource.open(DefaultDataSource.java:258) E/ExoPlayerImplInternal( 1409): at com.google.android.exoplayer2.upstream.StatsDataSource.open(StatsDataSource.java:84) E/ExoPlayerImplInternal( 1409): at com.google.android.exoplayer2.source.ProgressiveMediaPeriod$ExtractingLoadable.load(ProgressiveMediaPeriod.java:1005) E/ExoPlayerImplInternal( 1409): at com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:412) E/ExoPlayerImplInternal( 1409): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1137) E/ExoPlayerImplInternal( 1409): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:637) E/ExoPlayerImplInternal( 1409): at java.lang.Thread.run(Thread.java:1012) E/ExoPlayerImplInternal( 1409): Caused by: java.io.FileNotFoundException: flutter_assets/violet2.mp4 E/ExoPlayerImplInternal( 1409): at android.content.res.AssetManager.nativeOpenAsset(Native Method) E/ExoPlayerImplInternal( 1409): at android.content.res.AssetManager.open(AssetManager.java:904) E/ExoPlayerImplInternal( 1409): at com.google.android.exoplayer2.upstream.AssetDataSource.open(AssetDataSource.java:84) E/ExoPlayerImplInternal( 1409): ... 7 more E/flutter ( 1409): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: PlatformException(VideoError, Video player had error com.google.android.exoplayer2.ExoPlaybackException: Source error, null, null) E/flutter ( 1409): D/EGL_emulation( 1409): app_time_stats: avg=1372.88ms min=278.15ms max=2467.62ms count=2
实现代码如下:
import 'dart:async'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:video_player/video_player.dart'; class WelcomeScreen extends StatefulWidget { const WelcomeScreen({Key? key}) : super(key: key); @override State<WelcomeScreen> createState() => _WelcomeScreenState(); } class _WelcomeScreenState extends State<WelcomeScreen> { late VideoPlayerController _controller; bool _visible = false; @override void initState(){ super.initState(); SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp,]); final video = 'violet2.mp4'; _controller = VideoPlayerController.asset(video); _controller.addListener(() => setState(() {})); _controller.initialize().then((_) { _controller.setLooping(true); Timer(const Duration(milliseconds: 100), () { setState(() { _controller.play(); _visible = true; }); }); }); } @override void dispose() { super.dispose(); if (_controller != null) { _controller.dispose(); } } _getVideoBackground() { return AnimatedOpacity( opacity: _visible ? 1.0 : 0.0, duration: const Duration(milliseconds: 1000), child: VideoPlayer(_controller), ); } _getBackgroundColor() { return Container( color: Colors.white.withAlpha(120), ); } _getNextButton() { return <Widget> [ Container( alignment: Alignment.center, child: IconButton( onPressed: () { Navigator.pushNamed(context, 'login_screen'); _controller.dispose(); }, style: ElevatedButton.styleFrom( backgroundColor: Colors.white, ), icon: Icon(Icons.arrow_forward) ) ) ]; } _getContent() { return Column( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.start, children: <Widget>[ Spacer(), ..._getNextButton() ], ); } @override Widget build(BuildContext context) { return Scaffold( body: Center( child: Stack( children: <Widget>[ _getVideoBackground(), _getBackgroundColor(), _getContent(), ], ), ), ); } }
解决方案
从错误日志来看,核心问题是java.io.FileNotFoundException: flutter_assets/violet2.mp4,即无法找到指定的视频资源文件,按以下步骤排查修复:
1. 校验资源路径与pubspec.yaml配置
- 文件位置:确认
violet2.mp4的实际存放路径。如果放在项目根目录的assets文件夹下,初始化路径应改为'assets/violet2.mp4';若放在子文件夹(如assets/videos/),路径需对应为'assets/videos/violet2.mp4'。 - pubspec声明:必须在
pubspec.yaml中正确注册该资源,示例配置:flutter: assets: - assets/violet2.mp4 # 若需加载文件夹下所有文件,可写:- assets/videos/ - 刷新资源:执行
flutter pub get命令,然后重启应用(热重载无法加载新添加的资源)。
2. 添加初始化错误捕获
在初始化视频控制器时加入错误处理,避免未处理异常导致崩溃:
@override void initState(){ super.initState(); SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp,]); // 修正路径为正确的资源路径 final video = 'assets/violet2.mp4'; _controller = VideoPlayerController.asset(video); _controller.addListener(() => setState(() {})); _controller.initialize().then((_) { _controller.setLooping(true); Timer(const Duration(milliseconds: 100), () { setState(() { _controller.play(); _visible = true; }); }); }).catchError((error) { print('视频初始化失败: $error'); // 可在此处显示错误提示或切换为静态背景 }); }
3. 优化代码细节
- dispose方法:由于
_controller用late声明,无需判空,直接调用dispose即可:@override void dispose() { _controller.dispose(); super.dispose(); } - 视频格式兼容性:确保视频为ExoPlayer支持的格式(推荐MP4+H.264编码),避免使用不兼容的视频文件。
- 文件完整性:测试替换一个已知可用的视频文件,排除原文件损坏的可能。
内容的提问来源于stack exchange,提问作者Michele Sciacovelli
相关产品推荐
相关产品推荐

