#firebase #flutter #dart #google-cloud-firestore
#firebase #flutter #dart #google-облако-firestore
Вопрос:
Я пытаюсь воспроизвести видео с URL-адреса документа Firestore. Чтобы воспроизвести видео в Flutter, я должен создать его URL-адрес в методе init(). Я установил URL-адрес по умолчанию для видео с бабочками, и это значение должно было быть заменено URL-адресом, полученным из Firestore. (Чтобы мне было легко увидеть, работает ли код). Однако код не работает должным образом. Я получил сообщение об ошибке с надписью «NoSuchMethodError: получатель ‘value’ был вызван для null».
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// Create the initialization Future outside of build
final Future<FirebaseApp> _initialization = Firebase.initializeApp();
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: _initialization,
builder: (context, snapshot) {
// Check for error
if (snapshot.hasError) {
print(snapshot.error);
return Center(
child: Container(
child: Text(
"Something went wrong",
textDirection: TextDirection.ltr,
),
),
);
}
//Once complete, show your application
if (snapshot.connectionState == ConnectionState.done) {
return MaterialApp(
title: 'Flutter Demo',
home: VideoPlayerScreen(),
);
}
return CircularProgressIndicator();
});
}
}
class VideoPlayerScreen extends StatefulWidget {
@override
_VideoPlayerScreenState createState() => _VideoPlayerScreenState();
}
class _VideoPlayerScreenState extends State<VideoPlayerScreen> {
VideoPlayerController _controller;
Future<void> _initializeVideoPlayerFuture;
FirebaseFirestore firestore = FirebaseFirestore.instance;
String videoUrl =
'https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4';
@override
void initState() {
firestore.collection("videos").get().then((QuerySnapshot querySnapshot) => {
querySnapshot.docs.forEach((doc) {
// _controller.dispose();
videoUrl = doc["videoUrl"];
_controller = VideoPlayerController.network(videoUrl);
_initializeVideoPlayerFuture = _controller.initialize();
print(videoUrl);
})
});
// _controller = VideoPlayerController.network(videoUrl);
// _initializeVideoPlayerFuture = _controller.initialize();
super.initState();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Flutter Video Player"),
),
body: FutureBuilder(
future: _initializeVideoPlayerFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return Column(
children: [
AspectRatio(
aspectRatio: _controller.value.aspectRatio,
child: VideoPlayer(_controller),
),
],
);
} else {
return Center(child: CircularProgressIndicator());
}
},
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
if (_controller.value.isPlaying) {
_controller.pause();
} else {
_controller.play();
}
});
},
child: Icon(
_controller.value.isPlaying ? Icons.pause : Icons.play_arrow,
),
),
);
}
}
Ответ №1:
Попробуйте выполнить следующее:
@override
void initState() {
super.initState();
firestore.collection("videos").get().then((QuerySnapshot querySnapshot) => {
querySnapshot.docs.forEach((doc) {
videoUrl = doc["videoUrl"];
_controller = VideoPlayerController.network(videoUrl);
_initializeVideoPlayerFuture = _controller.initialize().then((_) {
// Ensure the first frame is shown after the video is initialized, even before the play button has been pressed.
setState(() {});
});
});
});
}
Поскольку initialize()
он асинхронный, вы можете использовать метод then
, который будет вызван при завершении future. Внутри обратного вызова вы можете вызвать setState()
, который вызовет перестройку и уведомит фреймворк о том, что внутреннее состояние виджетов изменилось.
Комментарии:
1. Спасибо. Сейчас это работает, но каждый раз, когда я перезапускаю приложение, страница с ошибкой отображается перед отображением видеопроигрывателя.
2. Что произойдет, когда вы полностью установите приложение? Попробуйте использовать
whenComplete
вместоthen
3. Он по-прежнему показывает ошибку до загрузки видеопроигрывателя.
4. проверьте этот pub.dev/packages/video_player , я никогда не использовал video_player, но у них есть свойство,
initialized
которое проверяет, инициализирован ли контроллер или нетchild: _controller.value.initialized ? AspectRatio( aspectRatio: _controller.value.aspectRatio, child: VideoPlayer(_controller), ) : Container(),
, вы можете использовать тот же способ в своем коде5. Я обнаружил проблему, которая находится в дочернем элементе плавающей кнопки действия. Поскольку контроллер не был инициализирован сначала, _controller.value . isPlaying выдаст ошибку. Большое вам спасибо!