如何在Flutter中播放视频列表?

时间:2019-04-02 03:34:14

标签: video dart flutter video-player

我正在使用抖动video_player包播放视频列表。

List sourceList;

sourceList = [
  {
    "size": 69742504,
    "name": "lucky-roulette.mp4",
    "mimetype": "video/mp4",
  },
  {
    "size": 69742504,
    "name": "BigBuckBunny.mp4",
    "mimetype": "video/mp4",
  }
];

我已经检出this issue,并对其进行了一些自定义代码。

void play() {
  log.fine("Now playing: $_nowPlayingUrl");
  _adController = VideoPlayerController.network(_nowPlayingUrl);
  _adController.initialize().then((_) => setState(() {}));
  _adController.play();
  _adController.addListener(checkIfVideoFinished);
}

void checkIfVideoFinished() {
  if (_adController == null ||
      _adController.value == null ||
      _adController.value.position == null ||
      _adController.value.duration == null) return;
  if (_adController.value.position.inSeconds ==
      _adController.value.duration.inSeconds) {
    _adController.removeListener(checkIfVideoFinished);
    _adController.dispose();
    // Change _nowPlayingIndex
    setState(() {
      _nowPlayingIndex = (_nowPlayingIndex + 1) % _totalIndex;
    });
    play();
  }
}

但是使用此代码段将发出异常Another exception was thrown: A VideoPlayerController was used after being disposed.

是否有更好的方法在Flutter中播放和循环播放视频列表?

2 个答案:

答案 0 :(得分:1)

您必须在Override dispose方法中调用视频控制器dispose方法。 removevideo时无需调用dispose方法。

答案 1 :(得分:0)

我还认为在处置Widget之前不调用dispose是可以的。

就我而言,我暂停了每个视频文件。我将FutureBuilder与VideoPlayerController一起使用。

依存关系
video_player: ^0.10.1
chewie: ^0.9.7
VideoPlayerController _controller;
ChewieController _chewieController; // custom ui
Future<void> _initializeVideoPlayerFuture;

var _clips = List<PoseClip>(); // video list
int _playingIndex = -1;
bool _disposed = false;
var _isPlaying = false;
var _isEndPlaying = false;

@override
void dispose() {
  _disposed = true;
  // By assigning Future is null,
  // prevent the video controller is using in widget before disposing that.
  _initializeVideoPlayerFuture = null;
  // In my case, sound is playing though controller was disposed.
  _controller?.pause()?.then((_){
    // dispose VideoPlayerController.
    _controller?.dispose();
  });
  super.dispose();
}


Future<bool> _clearPrevious() async {
  await _controller?.pause();
  _controller?.removeListener(_controllerListener);
  return true;
}

Future<void> _startPlay(int index) async {
  print("play ---------> $index");
  setState(() {
    _initializeVideoPlayerFuture = null;
  });
  Future.delayed(const Duration(milliseconds: 200), () {
    _clearPrevious().then((_){
      _initializePlay(index);
    });
  });
}

Future<void> _initializePlay(int index) async {
  final file = await _localStorage.localFile(_clips[index].filePath());
  print("file.exists: ${file.existsSync()}");
  print("file.path: ${file.path}");
  _controller = VideoPlayerController.file(file);
  _controller.addListener(_controllerListener);
  _chewieController = ChewieController(videoPlayerController: _controller);
  _initializeVideoPlayerFuture = _controller.initialize();

  setState(() {
    _playingIndex = index;
  });
}

// tracking status
Future<void> _controllerListener() async {
  if (_controller == null || _disposed) {
    return;
  }
  if (!_controller.value.initialized) {
    return;
  }
  final position = await _controller.position;
  final duration = _controller.value.duration;
  final isPlaying = position.inMilliseconds < duration.inMilliseconds;
  final isEndPlaying = position.inMilliseconds > 0 && position.inSeconds == duration.inSeconds;

  if (_isPlaying != isPlaying || _isEndPlaying != isEndPlaying) {
    _isPlaying = isPlaying;
    _isEndPlaying = isEndPlaying;
    print("$_playingIndex -----> isPlaying=$isPlaying / isCompletePlaying=$isEndPlaying");
    if (isEndPlaying) {
      final isComplete = _playingIndex == _clips.length - 1;
      if (isComplete) {
        print("played all!!");
      } else {
        _startPlay(_playingIndex + 1);
      }
    }
  }
}

// play view area
Widget _playView() {
  // FutureBuilder to display a loading spinner until finishes initializing
  return FutureBuilder(
    future: _initializeVideoPlayerFuture,
    builder: (BuildContext context, AsyncSnapshot snapshot) {
      if (snapshot.connectionState == ConnectionState.done) {
        _chewieController.play();
        return AspectRatio(
          aspectRatio: _controller.value.aspectRatio,
          child: Chewie(controller: _chewieController),
        );
      } else {
        return SizedBox(
          height: 300,
          child: Center(child: CircularProgressIndicator()),
        );
      }
    },
  );
}