使用 future.then() 消耗 Future 的结果似乎只存在于 .then function() 中

问题描述

我正在构建一个应用作为大学项目,其中一项要求是在应用内播放视频。

我有存储在 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();
}

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...