Q:

Flutter can not dispose VideoPlayerController

I am getting an exception thrown while using a back button after disposing of my VideoPlayerController.
I have my VideoPlayer and VideoPlayerController set up like this:
 String url;
 var plan;
_VideoPlayerScreenState(this.url,{this.plan});

 Future<Null> OnWillPop(){

_controller.dispose();

if(plan!=null)
Navigator.push(context, MaterialPageRoute(builder: (context)=>
ListSession(plan :plan)));
else
  Navigator.push(context, MaterialPageRoute(builder: (context)=>
ListMoves()));

}
VideoPlayerController _controller;
Future<void> _initializeVideoPlayerFuture;

@override
void initState() {
 _controller = VideoPlayerController.network(
  url,
 );

// Initialize the controller and store the Future for later use.
_initializeVideoPlayerFuture = _controller.initialize();

// Use the controller to loop the video.
_controller.setLooping(true);
_controller.play();
super.initState();
}

@override
void dispose() {
 print("+++++++++++++++++++++++++++++++++++++++++++");
_controller.dispose();
 super.dispose();
}

 @override
 Widget build(BuildContext context) {
 return WillPopScope(onWillPop: OnWillPop,child:Scaffold(

   // Use a FutureBuilder to display a loading spinner while waiting for the
   // VideoPlayerController to finish initializing.
   body: 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 Center(
          child: AspectRatio(
            aspectRatio: _controller.value.aspectRatio,
            // Use the VideoPlayer widget to display the video.
            child: VideoPlayer(_controller),
          ),
        );
      } else {
        // If the VideoPlayerController is still initializing, show a
        // loading spinner.
        return Center(child: CircularProgressIndicator());
      }
    },
  ),
 ));
}

but when I press the back button, I get this error:
Another exception was thrown: A VideoPlayerController was used after being disposed.

How do I properly dispose of my VideoPlayerController and be able to incorporate the back button?

A:

You can copy paste run full code below 
and mark unmark Navigator.push / Navigator.pushReplacement to check effect 
In your case, you do not need to dispose of controller, because controller is local to this page, you can just do _controller.pause() 
You use Navigator.push go to next page means you will pop from next page 
If you dispose controller and set controller to null successfully, when pop from next page, you will get an error because initState will not be called again, controller will not init again 
If you use Navigator.pushReplacement, dispose will be called automatically, 
You can see console show _controller.dispose in demo code. 
working demo 
you can see when back from ListMove page, video still can play 

full code
import 'dart:async';

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

void main() => runApp(VideoPlayerApp());

class VideoPlayerApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Video Player Demo',
      home: VideoPlayerScreen(),
    );
  }
}

class VideoPlayerScreen extends StatefulWidget {
  VideoPlayerScreen({Key key}) : super(key: key);

  @override
  _VideoPlayerScreenState createState() => _VideoPlayerScreenState();
}

class _VideoPlayerScreenState extends State<VideoPlayerScreen> {
  VideoPlayerController _controller;
  VideoPlayerController _oldController;
  Future<void> _initializeVideoPlayerFuture;

  @override
  void initState() {
    print("initState");
    // Create and store the VideoPlayerController. The VideoPlayerController
    // offers several different constructors to play videos from assets, files,
    // or the internet.
    _controller = VideoPlayerController.network(
      'https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4',
    );

    // Initialize the controller and store the Future for later use.
    _initializeVideoPlayerFuture = _controller.initialize();

    // Use the controller to loop the video.
    _controller.setLooping(true);

    super.initState();
  }

  @override
  void dispose() {
    print("_controller.dispose");
    // Ensure disposing of the VideoPlayerController to free up resources.
    //_initializeVideoPlayerFuture = null;
    _controller.dispose();

    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () async {
        await _controller.pause();
        Navigator.push(
            context, MaterialPageRoute(builder: (context) => ListMoves()));

        /*Navigator.pushReplacement(
            context, MaterialPageRoute(builder: (context) => ListMoves()));*/
      },
      child: Scaffold(
        appBar: AppBar(
          title: Text('Butterfly Video'),
        ),
        // Use a FutureBuilder to display a loading spinner while waiting for the
        // VideoPlayerController to finish initializing.
        body: 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: _controller.value.aspectRatio,
                // Use the VideoPlayer widget to display the video.
                child: VideoPlayer(_controller),
              );
            } else {
              // If the VideoPlayerController is still initializing, show a
              // loading spinner.
              return Center(child: CircularProgressIndicator());
            }
          },
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            // Wrap the play or pause in a call to `setState`. This ensures the
            // correct icon is shown.
            setState(() {
              // If the video is playing, pause it.
              if (_controller.value.isPlaying) {
                _controller.pause();
              } else {
                // If the video is paused, play it.
                _controller.play();
              }
            });
          },
          // Display the correct icon depending on the state of the player.
          child: Icon(
            _controller.value.isPlaying ? Icons.pause : Icons.play_arrow,
          ),
        ), // This trailing comma makes auto-formatting nicer for build methods.
      ),
    );
  }
}

class ListMoves extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('List Movies'),
      ),
      body: Center(
        child: RaisedButton(
          child: Text('Launch screen'),
          onPressed: () {},
        ),
      ),
    );
  }
}

