Результат потребления Future с future.then (), кажется, живет только внутри функции .then ()

Я создаю приложение как проект для университета, и одно из требований - воспроизводить видео в приложении.

У меня есть ссылки на видео с упражнениями (сгибания бицепса и т. Д.), Хранящиеся в столбце таблицы в 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,
        ),
      ),
    );
  }
}

Я пытаюсь использовать то, что возвращается методом, и присвоить значение столбца локальному _exerciseVideoLink а затем используйте эту строку для инициализации с помощью ссылки, содержащейся внутри.

Реализация getExerciseById(int id) следующее:

          Future<Exercise> getExerciseById(int id) {
        return (select(exercises)..where((exercise) => exercise.exerciseId.equals(id))).getSingle();
    }

Моя проблема прямо сейчас заключается в том, что после использования и присвоения его атрибута упражненийVideoLink локальной переменной String переменная становится нулевой, как только .then((value) => ... функция завершена, и, следовательно, инициализация не выполняется, потому что URI равен нулю.

Это почему? Как мне сделать так, чтобы я мог потреблять Future<Exercise> и использовать его exerciseVideoLink чтобы передать его VideoPlayerController?

1 ответ

Ваш _controller зависит от результата getExerciseById()поэтому вам нужно дождаться его завершения, прежде чем вы сможете его назначить. Вы можете найти 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();
}
Другие вопросы по тегам