Flutter video_player с URL-адресом из документа Firestore

#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() , который вызовет перестройку и уведомит фреймворк о том, что внутреннее состояние виджетов изменилось.

https://pub.dev/packages/video_player

Комментарии:

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 выдаст ошибку. Большое вам спасибо!