问题描述
我正在构建一个应用作为大学项目,其中一项要求是在应用内播放视频。
我有存储在 SQLite 表格列中的锻炼视频(二头肌弯举等)的链接。
我使用 Moor 来与数据库交互。
我有以下屏幕,我试图在其中播放数据库链接中引用的视频:
class ExerciseVideoTab extends StatefulWidget {
final int exerciseId;
ExerciseVideoTab(this.exerciseId);
@override
_ExerciseVideoTabState createState() => _ExerciseVideoTabState();
}
class _ExerciseVideoTabState extends State<ExerciseVideoTab> {
VideoPlayerController _controller;
Future<void> _initializeVideoPlayerFuture;
String _exerciseVideoLink;
@override
void initState() {
super.initState();
locator<MoorDB>().getExerciseById(widget.exerciseId).then((value) =>
_exerciseVideoLink = value.exerciseVideoLink);
_controller = VideoPlayerController.network(_exerciseVideoLink.toString());
_initializeVideoPlayerFuture = _controller.initialize();
print(_exerciseVideoLink); // prints null for some reason
}
@override
void dispose() {
// Ensure disposing of the VideoPlayerController to free up resources.
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(child: FutureBuilder(
future: _initializeVideoPlayerFuture,builder: (context,snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
// If the VideoPlayerController has finished initialization,use
// the data it provides to limit the aspect ratio of the video.
return AspectRatio(
aspectRatio: _controller.value.aspectRatio,// Use the VideoPlayer widget to display the video.
child: VideoPlayer(_controller),);
} else {
// If the VideoPlayerController is still initializing,show a
// loading spinner.
return Center(child: CircularProgressIndicator());
}
}
)
),floatingActionButton: FloatingActionButton(
onPressed: () {
// Wrap the play or pause in a call to `setState`. This ensures the
// correct icon is shown.
setState(() {
// If the video is playing,pause it.
if (_controller.value.isPlaying) {
_controller.pause();
} else {
// If the video is paused,play it.
_controller.play();
}
});
},// Display the correct icon depending on the state of the player.
child: Icon(
_controller.value.isPlaying ? Icons.pause : Icons.play_arrow,),);
}
}
我正在尝试使用 Future<Exercise>
方法返回的 getExerciseById(int id)
并将 exerciseVideoLink
列值分配给本地 _exerciseVideoLink
,然后使用该字符串进行初始化包含链接的 VideoPlayerController
。
getExerciseById(int id)
的实现如下:
Future<Exercise> getExerciseById(int id) {
return (select(exercises)..where((exercise) => exercise.exerciseId.equals(id))).getSingle();
}
我现在的问题是,在消耗了 Future<Exercise>
并将其运动视频链接属性分配给本地 String 变量后,一旦 .then((value) => ...
函数结束,该变量立即变为空,因此,初始化VideoPlayerController
失败,因为 URI 为空。
这是为什么?我如何才能使用 Future<Exercise>
并使用它的 exerciseVideoLink
以将其传递给 VideoPlayerController
?
解决方法
您的 _controller
取决于 getExerciseById()
的结果,因此您需要等待 Future
完成才能分配它。在处理大量嵌套的 async
时,您可能会发现 await
/Future
语法更易于阅读。
一个示例实现可以是:
@override
void initState() {
super.initState();
_init(); // split out a separate method,initState cannot be async
}
Future<void> _init() async {
final exercise = await locator<MoorDB>().getExerciseById(widget.exerciseId);
_controller = VideoPlayerController.network(exercise.exerciseVideoLink.toString());
_initializeVideoPlayerFuture = _controller.initialize();
}