admin管理员组

文章数量:1316023

I have two views HomeView and JokeView. On the HomeView I have a button that opens JokeView:

 ElevatedButton(
                onPressed: () {
                  Navigator.of(context).push(
                    MaterialPageRoute(builder: (context) => const JokeView(), maintainState: false),
                  );
                },
                child: Text('Joke view'))

On JokeView I have a BackButton that closes the view

AppBar(
        leading: BackButton(
          onPressed: () {
             Navigator.of(context).pushReplacement(
                    MaterialPageRoute(builder: (context) => const HomeView(), maintainState: false));
          },

On JokeView I also has the ListenableBuilder that listens to JokeViewModel which is a ChangeNotifier

ListenableBuilder(
           listenable: jokeViewModel,

The JokeViewModel has the dispose() method:

class JokeViewModel with ChangeNotifier {
 ...
  @override
  void dispose() {
    print("dispose is called");
    super.dispose();
  }
}

I expect this method to be called when JokeView is removed from the stack, but it never happens. I tried the default backButton, Navigator.pop, Navigator.pushReplacement.

Am I doing something wrong? Is it supposed to work? I mean should the framework call this method when the view is popping from the stack or not?

The question is educational and I am aware of StatefulWidgets. I don't use Provider.

I have two views HomeView and JokeView. On the HomeView I have a button that opens JokeView:

 ElevatedButton(
                onPressed: () {
                  Navigator.of(context).push(
                    MaterialPageRoute(builder: (context) => const JokeView(), maintainState: false),
                  );
                },
                child: Text('Joke view'))

On JokeView I have a BackButton that closes the view

AppBar(
        leading: BackButton(
          onPressed: () {
             Navigator.of(context).pushReplacement(
                    MaterialPageRoute(builder: (context) => const HomeView(), maintainState: false));
          },

On JokeView I also has the ListenableBuilder that listens to JokeViewModel which is a ChangeNotifier

ListenableBuilder(
           listenable: jokeViewModel,

The JokeViewModel has the dispose() method:

class JokeViewModel with ChangeNotifier {
 ...
  @override
  void dispose() {
    print("dispose is called");
    super.dispose();
  }
}

I expect this method to be called when JokeView is removed from the stack, but it never happens. I tried the default backButton, Navigator.pop, Navigator.pushReplacement.

Am I doing something wrong? Is it supposed to work? I mean should the framework call this method when the view is popping from the stack or not?

The question is educational and I am aware of StatefulWidgets. I don't use Provider.

Share Improve this question asked Jan 29 at 23:01 Yuriy N.Yuriy N. 6,1472 gold badges46 silver badges41 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 1

Objects that mix in ChangeNotifier are a common place where developers work with state and resources that will of course use memory. If these objects are not managed properly during the application's lifecycle, it will lead to memory leaks.

Therefore ChangeNotifier is disposable and internally in Flutter during debug it uses FlutterMemoryAllocations.instance.dispatchObjectCreated and FlutterMemoryAllocations.instance.dispatchObjectDisposed to help us, developers, identify potential memory leaks.

However, ChangeNotifier.dispose() method is not always called by the framework. It depends on how the object was created.

If you create it like:

final jokeViewModel = JokeViewModel();

it becomes your responsibility to call the dispose method. Maybe you want this object to be long lived and keep it somewhere as a singleton or maybe you want it to have the same lifecycle scope as the host StatefulWidget, in which case you call dispose when the host widget is disposed.

If you use Provider, you can also provide an instance of your ChangeNotifier in a widget tree. There are two ways to do this:

  1. Delegate the object creation to the ChangeNotifierProvider:
ChangeNotifierProvider(
   create: (context) => JokeViewModel(...),
   child: ...
)

In this case, it becomes the responsibility of the ChangeNotifierProvider to call dispose on the instance of ChangeNotifier that it creates. This happens when the ChangeNotifierProvider itself is disposed.

  1. Provide an existing instance of a ChangeNotifier:
ChangeNotifierProvider.value(
  value: jokeViewModelCreatedElsewhere,
  child: ...
)

In this case, the ChangeNotifierProvider can not and will not be responsible for calling dispose on the jokeViewModelCreatedElsewhere because it does not own it. Disposing it could lead to errors if the intention of the caller was to share this instance with multiple widgets (eg. you have a ChangeNotifier that is used in multiple modals, it doesn't make sense for the first modal to dispose it when it's closed).

本文标签: flutterThe ChangeNotifier has a dispose() method When does it get calledStack Overflow