Why does the video player's dispose method get triggered upon entering fullscreen mode?

107 views Asked by At

I have four files

  • home_page.dart: home_page.dart showcases images and text. Upon clicking, it passes the video URL to webview_page.dart.
  • webview_page.dart: Upon receiving the nativeVid (video URL) from home_page.dart, webview_page.dart forwards this information to video_player.dart.
  • video_player.dart: video_player.dart utilizes the nativeVid (video URL) to initiate video playback.
  • video_tv_fullscreen.dart: When the player enters fullscreen mode, video_tv_fullscreen.dart takes effect.

Question: The functionality operates smoothly until the transition to fullscreen mode. Upon initiating fullscreen, the dispose method in video_player.dart is triggered, video can't be play anymore. Why does this occur? If there is not in fullscreen mode the video works well.

home_page.dart

import 'package:xxxxx/pages/webview/webview_page.dart';

...

String webviewUrl = Constant.shareUrl + '12345';
Navigator.of(context).push(SlideAnimationRoute(
  builder: (_) {
    return WebViewPage(webviewUrl, isFromNative: true);
  },
));

webview_page.dart

import 'package:xxxxx/pages/webview/video_player.dart';

...

@override
Widget build(BuildContext context) {
  return WillPopScope(
    child: Stack(
      children: <Widget>[
        Scaffold(
          backgroundColor: Colors.transparent,
          body: Builder(builder: (BuildContext context) {
            return Container(
              height: MediaQuery.of(context).size.width * 9.0 / 16,
              child: VideoPlayer(
                key: _refreshKey,
                VideoDetailPageParamsBean.createInstance(
                  vid: nativeVid,
                  enterSource:
                      VideoDetailsEnterSource.VideoDetailsEnterSourceHome,
                ),
                webviewVid: nativeVid,
              ),
            );
          }),
        ),
      ],
    ),
  );
}

video_player.dart:

import 'package:xxxxx/pages/video/player/video_tv_fullscreen.dart';

class _VideoPlayerState extends State<VideoPlayer>
  with SingleTickerProviderStateMixin, RouteAware, WidgetsBindingObserver {

  VideoPlayerController? _videoPlayerController;
  ChewieController? _chewieController;

  void initState() {
    super.initState();
    .....
    _initPageData();
  }

  void _initPageData() async {
    .....
    _initVideoPlayers(
            _videoDetailPageParamsBean.getVideoSource, false, startAt);
    .....
  }

  Future<void> _initVideoPlayers(
      String videoUrl, bool isFullScreen, Duration startAt) async {
    _isVideoReportSuccess = false;
    _videoPlayerController = VideoPlayerController.network(videoUrl);
    _hasReportedVideoPlay = false;
    _videoLoadStartTime = DateTime.now();
    try {
      await _videoPlayerController?.initialize().then((_) {
        setState(() {
          _chewieController = ChewieController(
            videoPlayerController: _videoPlayerController!,
            aspectRatio: _videoPlayerController?.value.aspectRatio,
            autoPlay: true,
            startAt: startAt,
            looping: false,
            showControlsOnInitialize: false,
            allowMuting: false,
            isLive: _videoPlayerController?.value.duration == Duration.zero,
            routePageBuilder: VideoTvFullScreenBuilder.of(
                _videoPlayerController?.value.aspectRatio ?? 0),
            deviceOrientationsAfterFullScreen: [DeviceOrientation.portraitUp],
            isInitFullScreen: isFullScreen,
          );
          _isVideoChangedInit = true;
          _videoPlayerController?.addListener(videoPlayerChanged);
        });
      });
    } catch (e) {
      print('Error $e');
    }
  }
  @override
  Widget build(BuildContext context) {
    ......
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    VideoDetailDataMgr.instance.clearCachedDataByKey(_pageFlag);
    routeObserver.unsubscribe(this);
    _chewieController?.dispose();
    clearVideoPlayerController();
    super.dispose();
  }

  void clearVideoPlayerController() {
    _videoPlayerController?.pause();
    _videoPlayerController?.dispose();
  }
}

video_tv_fullscreen.dart

import 'package:flutter/material.dart';
import 'package:chewie/chewie.dart';

class VideoTvFullScreenBuilder {
  final double aspect;

  VideoTvFullScreenBuilder(this.aspect);

  AnimatedWidget build(BuildContext context, Animation<double> animation,
      Animation<double> secondaryAnimation, dynamic controllerProvider) {
    return AnimatedBuilder(
      animation: animation,
      builder: (BuildContext context, Widget? child) {
        return _buildFullScreenVideo(context, animation, controllerProvider);
      },
    );
  }

  Widget _buildFullScreenVideo(BuildContext context,
      Animation<double> animation, dynamic controllerProvider) {
    return Scaffold(
      resizeToAvoidBottomInset: false,
      body: Container(
          alignment: Alignment.center,
          decoration: BoxDecoration(
            gradient: LinearGradient(
              begin: Alignment.topCenter,
              end: Alignment.bottomCenter,
              colors: [Color.fromRGBO(84, 84, 84, 1.0), Colors.black],
            ),
          ),
          child: Container(
              height: MediaQuery.of(context).size.width / aspect,
              child: ClipRect(
                child: controllerProvider,
              ))),
    );
  }

  static ChewieRoutePageBuilder of(double aspect) {
    return VideoTvFullScreenBuilder(aspect).build;
  }
}
1

There are 1 answers

2
Meet Prajapati On

It sounds like you're facing an issue where enabling fullscreen mode in your app leads to a screen rotation and recreation of the activity, causing your player to be disposed.