fluttercommunity / chewie

The video player for Flutter with a heart of gold
MIT License
1.94k stars 1.01k forks source link

Controller not disposing when navigating away #233

Open fiixed opened 4 years ago

fiixed commented 4 years ago

Hi,

when I pop off the videoplayer screen, it seems neither the videoplayer controller or the chewie controller are being disposed (I can still hear the video playing from the new screen).

Here is my code:

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

class AddVideoScreen extends StatefulWidget {
  static const routeName = '/add-video';
  @override
  _AddVideoScreenState createState() => _AddVideoScreenState();
}

class _AddVideoScreenState extends State<AddVideoScreen> {
  final _titleController = TextEditingController();
  VideoPlayerController _videoPlayerController;
  ChewieController _chewieController;
  Future<void> _initializeVideoPlayerFuture;
  String videoPath;

  @override
  void initState() {
    super.initState();
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    videoPath = ModalRoute.of(context).settings.arguments as String;

    _videoPlayerController = VideoPlayerController.file(File(videoPath));

    _chewieController = ChewieController(
      videoPlayerController: _videoPlayerController,
      aspectRatio: 2 / 3,
      autoPlay: true,
      looping: true,

    );
  }

  @override
  void dispose() {
    _videoPlayerController.dispose();
    _videoPlayerController = null;
    _chewieController.dispose();
    _chewieController = null;
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        appBar: AppBar(
          leading: Container(),
          title: Text('Add a New Video'),
        ),
        body: SingleChildScrollView(
          child: Padding(
            padding: const EdgeInsets.all(8.0),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.stretch,
              //mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: <Widget>[
                TextField(
                  decoration: InputDecoration(labelText: 'Title'),
                  controller: _titleController,
                ),
                SizedBox(
                  height: 10.0,
                ),
                Center(
                  child: Chewie(
                    controller: _chewieController,

                  ),
                ),
                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: _videoPlayerController.value.aspectRatio,
                        // Use the VideoPlayer widget to display the video.
                        child: Chewie(
                          controller: _chewieController,
                        ),
                      );
                    } else {
                      return Container();
                      // If the VideoPlayerController is still initializing, show a
                      // loading spinner.
                      //return Center(child: CircularProgressIndicator());
                    }
                  },
                ),
                RaisedButton.icon(
                  icon: Icon(Icons.delete),
                  label: Text('Delete Video'),
                  elevation: 0,
                  materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
                  color: Theme.of(context).errorColor,
                  onPressed: () {

                    Navigator.of(context).pop();
                  },
                ),
                RaisedButton.icon(
                  icon: Icon(Icons.add),
                  label: Text('Add Video'),
                  elevation: 0,
                  materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
                  color: Theme.of(context).accentColor,
                  onPressed: () {},
                ),
              ],
            ),
          ),
        ),

      ),
    );
  }
}
fiixed commented 4 years ago

I tried putting a SetState before I pop and it improved it a little but I can break it soon enough by going between screens quickly.

onPressed: () {
                    setState(() {
                      _videoPlayerController.dispose();
                      _videoPlayerController = null;
                      _chewieController.dispose();
                      _chewieController = null;
                    });
                    Navigator.of(context).pop();
                  },
jinyus commented 4 years ago

I solved this issue by using the VisibilityDetector to pause the player when it's not on the screen.

` VisibilityDetector(

    key: Key('someUniqueString'),
    onVisibilityChanged: (VisibilityInfo info) {
      if (info.visibleFraction == 0 && mounted) {
        //checks if the player is visible and it hasn't been disposed as yet(mounted) and
        //pause the chewie player, you could dispose here too');
        _chewieController.pause();
      }
    },
    child:Chewie(
        controller: _chewieController,
      ),
  );

`