0

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

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

我现在的问题是,在使用并将其 exerciseVideoLink 属性分配给本地 String 变量后,该变量在函数结束后Future<Exercise>立即变为空,因此,由于 URI 为空,初始化失败。.then((value) => ...VideoPlayerController

这是为什么?我怎样才能做到这一点,以便我可以消费Future<Exercise>并使用它exerciseVideoLink来将它传递给VideoPlayerController

4

1 回答 1

0

_controller取决于结果,getExerciseById()因此您需要等待该结果Future完成才能分配它。当使用大量嵌套的 s时,您可能会发现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();
}
于 2021-06-05T00:33:02.823 回答