FilledStacks / flutter-tutorials

The repo contains the source code for all the tutorials on the FilledStacks Youtube channel.
MIT License
4.75k stars 1.76k forks source link

Dispose Issue on Tab Container #9

Closed VictorUvarov closed 5 years ago

VictorUvarov commented 5 years ago

Demo: https://github.com/VictorUvarov/disposeDemo

FilledStacks commented 5 years ago

Thanks for the Demo @VictorUvarov I'll check it out a bit later and let you know what's up. Based on the code my current guess is that setState is being called when the future delay in the init call has completed. And at that point the model has been disposed. I'll override the dispose then keep track internally on if it's been disposed and use that to prevent certain pieces of logic from running. Or you can keep your future as a member variable, make it cancellable and cancel it in the dispose call.

Could you try one of those solutions and see if it works. Just to see if it is that.

add a bool to your model

bool disposed = false;

override the dispose call and set it to true. Then in your init function in the model check


if(!disposed) {
setState(...)
}
VictorUvarov commented 5 years ago

I added and pushed the dispose flag to the base model. This seems to fix the issue. I don't like that I need to do that but it seems to work.

bool disposed = false;

  void setState(ViewState viewState) {
    _state = viewState;

    if (disposed) return;

    notifyListeners();
  }

  @override
  void dispose() {
    disposed = true;

    super.dispose();
  }
FilledStacks commented 5 years ago

It comes with the problem, if you're disposing your tabs every time you switch between then you have to make sure all their activity stops when complete.

There's a few other things you can try to see which one you like.

  1. Keep a reference to your Future as a CancelableOperation , in dispose cancel that operation.
  2. Make your model instance a singleton and never dispose it. Pass a optional keepAlive boolean that's false by default. In the dispose override only call super.dispose when it's true
  3. Do it at the Provider level. The ChangeNotifierProvider can take in a disposer, in the base view supply your disposer and using the logic from 2 only call the dispose method if required for that model.

If this is something that's common in your app then the architecture should make it as easy, if not invisible to you based on some flags you set. Some apps require more "red tape" than others.

I hope you find a good solution for it 👍

am-singh commented 5 years ago

@VictorUvarov just out of curiosity: what is bad with your solution? it is simple and does not waste many resources.

hayribakici commented 5 years ago

@VictorUvarov Is it not possible to recreate the disposed model at the Provider level? I recall this is quite common in dependency injection, that the required objects are just recreated when disposed.