Результат потребления 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();
}