I know passing context to closure sometimes may cause a serious memory leak. Should i always avoid it or there are cases when it is ok? In my case I need to show dialog. Here is the options I see:
- Stateless widget with closure that stores context:
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MyCoolButton(
onTap: () async {
unawaited(
showDialog(
context: context,
builder: (context) => MyDialog(),
),
);
},
);
}
}
- Stateful widget with a member-handler:
class MyWidget extends StatefulWidget {
const MyWidget({Key? key}) : super(key: key);
@override
State<SecondaryControls> createState() => _SecondaryControlsState();
}
class _MyWidgetState extends State<MyWidget> {
void _openDialog() async {
await showDialog(
context: context,
builder: (context) => MyDialog(),
);
}
@override
Widget build(BuildContext context) {
return MyCoolButton(
onTap: _openDialog,
);
}
}
CodePudding user response:
I know passing context to closure can cause a serious memory leak.
This is a misunderstanding.
You should always avoid saving/caching BuildContext
as it might cause a situation where the context is detached at the time it is needed. Passing a context is pretty common. Say you build a Widget
that takes in a WidgetBuilder
as a parameter, that builder function/closure will be called with the context from the Widget
s build
method. Passing in a context into showDialog
is unavoidable but also not an issue.
Generally, in code bases I work in, it's forbidden to pass a build context to a constructor. It is always preferred to pass in the thing the build context is used to access.
CodePudding user response:
There is nothing wrong with passing a BuildContext to functions in this manner, otherwise showDialog wouldn't have been designed like that.
There is also no such thing as a memory leak in Dart, the garbage collector can handle closures and circular references just fine.