Skip to content

Instantly share code, notes, and snippets.

@nashfive
Last active March 30, 2020 10:38
Show Gist options
  • Save nashfive/221d42f266b1a4590b44bab322bb8afb to your computer and use it in GitHub Desktop.
Save nashfive/221d42f266b1a4590b44bab322bb8afb to your computer and use it in GitHub Desktop.
Provider error with ChangeNotifierProvider and Navigator.popUntil
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() => runApp(MyApp());
class Store extends ChangeNotifier {
final createdAt = DateTime.now();
dispose() {
print("store.dispose()");
super.dispose();
}
Store() {
print(toString());
}
@override
String toString() {
return 'Store{createdAt: $createdAt}';
}
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is Store &&
runtimeType == other.runtimeType &&
createdAt == other.createdAt;
@override
int get hashCode => createdAt.hashCode;
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Home(),
routes: {
'feature': (_) => ChangeNotifierProvider(
create: (_) => Store(),
child: Feature(),
),
},
);
}
}
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: RaisedButton(
child: Text("Feature"),
onPressed: () => Navigator.of(context).pushNamed('feature'),
),
),
);
}
}
class Feature extends StatelessWidget {
@override
Widget build(BuildContext context) {
final store = Provider.of<Store>(context, listen: false);
return Scaffold(
appBar: AppBar(title: Text("FEATURE")),
body: Center(
child: RaisedButton(
child: Text('Next'),
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => ChangeNotifierProvider.value(
value: store,
child: Confirm(),
),
),
);
},
),
),
);
}
}
class Confirm extends StatelessWidget {
@override
Widget build(BuildContext context) {
final store = Provider.of<Store>(context, listen: false);
return Scaffold(
appBar: AppBar(title: Text("CONFIRM")),
body: Center(
child: RaisedButton(
child: Text('Next'),
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => ChangeNotifierProvider.value(
value: store,
child: Finish(),
),
),
);
},
),
),
);
}
}
class Finish extends StatelessWidget {
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async => false,
child: Scaffold(
body: Center(
child: RaisedButton(
child: Text("Close"),
onPressed: () {
Navigator.of(context).popUntil(ModalRoute.withName('/'));
},
),
),
),
);
}
}
@nashfive
Copy link
Author

nashfive commented Mar 30, 2020

First run is fine, second (and following) run has an exception:

flutter: Store{createdAt: 2020-03-30 12:28:04.415600}
flutter: store.dispose()
flutter: Store{createdAt: 2020-03-30 12:28:08.965431}
flutter: store.dispose()

════════ Exception caught by widgets library ═══════════════════════════════════════════════════════
The following assertion was thrown while finalizing the widget tree:
A Store was used after being disposed.

Once you have called dispose() on a Store, it can no longer be used.
When the exception was thrown, this was the stack: 
#0      ChangeNotifier._debugAssertNotDisposed.<anonymous closure> (package:flutter/src/foundation/change_notifier.dart:105:9)
#1      ChangeNotifier._debugAssertNotDisposed (package:flutter/src/foundation/change_notifier.dart:111:6)
#2      ChangeNotifier.removeListener (package:flutter/src/foundation/change_notifier.dart:166:12)
#3      ListenableProvider._startListening.<anonymous closure> (package:provider/src/listenable_provider.dart:88:25)
#4      _ValueInheritedProviderState.dispose (package:provider/src/inherited_provider.dart:569:22)
...
════════════════════════════════════════════════════════════════════════════════════════════════════

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment