Looking up a deactivated widget's ancestor is unsafe
Asked Answered
B

22

124

I am new in Flutter and I am trying receive data with a Dialog. When a click in textField the error of image2 appear...

Layout's Image Error's Image

show(BuildContext context){

    var dialog = Dialog(
      child: Container(
        margin: EdgeInsets.all(8.0),
        child: Form(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              TextFormField(
                decoration: InputDecoration(
                    labelText: "Insira o número de telefone",
                    border: OutlineInputBorder(
                        borderRadius: BorderRadius.all(Radius.circular(2.0)))),
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.end,
                children: <Widget>[
                  FlatButton(
                      onPressed: () {
                        Navigator.of(context).pop();
                      },
                      child: Text("Cancelar")),
                  FlatButton(
                      onPressed: () {
                        Navigator.of(context).pop();
                      },
                      child: Text("Aceitar"))
                ],
              )
            ],
          ),
        ),
      ),
    );

    showDialog(context: context,builder: (context){
      return dialog;
    });
  }

This is my code.

I/flutter (31032): Looking up a deactivated widget's ancestor is unsafe.
I/flutter (31032): At this point the state of the widget's element tree is no longer stable. To safely refer to a
I/flutter (31032): widget's ancestor in its dispose() method, save a reference to the ancestor by calling
I/flutter (31032): inheritFromWidgetOfExactType() in the widget's didChangeDependencies() method.
I/flutter (31032): 
Bonze answered 10/2, 2019 at 14:36 Comment(0)
P
118

Declare a global variable

    final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();

then register the key on your widget build's scaffold eg

    @override
    Widget build(BuildContext context) {
     return Scaffold(
       key: _scaffoldKey,
       ...

then on the dialog

show(BuildContext context){

var dialog = Dialog(
  child: Container(
    margin: EdgeInsets.all(8.0),
    child: Form(
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          TextFormField(
            decoration: InputDecoration(
                labelText: "Insira o número de telefone",
                border: OutlineInputBorder(
                    borderRadius: BorderRadius.all(Radius.circular(2.0)))),
          ),
          Row(
            mainAxisAlignment: MainAxisAlignment.end,
            children: <Widget>[
              FlatButton(
                  onPressed: () {
                    Navigator.of(context).pop();
                  },
                  child: Text("Cancelar")),
              FlatButton(
                  onPressed: () {
                    Navigator.of(context).pop();
                  },
                  child: Text("Aceitar"))
            ],
          )
        ],
      ),
    ),
  ),
);

Pass that scaffold context to the showDialog method

showDialog(context: _scaffoldKey.currentContext ,builder: (context){
  return dialog;
 });
}
Pragmatics answered 12/9, 2019 at 14:53 Comment(4)
thanks! this helped me with one of my dialogs, but i have another page which whenever loggs in successfully i pop using navigator.of(context)..pop()..pop()..pop("yes") but when dialog is shown i face this error, i used a scaffold key and also the builder.Buoyant
This works for me having a big calling project.. which has multiple roles types .. passing scaffold.currentContext! has solved the issues as I was using the function for multiple roles of pages. Kudos to solution !!Paviour
Thanks for the answer! Can you explain why this works a bit?Eustoliaeutectic
Navigator.of(_scaffoldKey.currentContext!).pop(); to close dialogBelsen
L
74

Try This

Give different context name for dialog

 showDialog(context: context,builder: (dialogContex){
              return Dialog(
                child: Container(
                  margin: EdgeInsets.all(8.0),
                  child: Form(
                    child: Column(
                      mainAxisSize: MainAxisSize.min,
                      children: <Widget>[
                        TextFormField(
                          decoration: InputDecoration(
                              labelText: "Insira o número de telefone",
                              border: OutlineInputBorder(
                                  borderRadius: BorderRadius.all(Radius.circular(2.0)))),
                        ),
                        Row(
                          mainAxisAlignment: MainAxisAlignment.end,
                          children: <Widget>[
                            FlatButton(
                                onPressed: () {
                                  Navigator.of(dialogContex).pop();
                                },
                                child: Text("Cancelar")),
                            FlatButton(
                                onPressed: () {
                                  Navigator.of(context).pop();
                                },
                                child: Text("Aceitar"))
                          ],
                        )
                      ],
                    ),
                  ),
                ),
              );
            });
Lara answered 28/8, 2019 at 13:50 Comment(3)
this answer is technically right as we need to remove dialog so we should give diffrent name to dialog contextVirgy
Exactly what I was looking for. I have a dialog with edit text fields and also a loading dialog, naming the contexts separates them and I am able to close both successfully!Warms
You can create a buildContext variable and assign context to it. Then you can pass that newly created variable to showDialog method.Manage
M
28

I got the same error when attempting to open a dialog and I found a solution here: github flutter issues. Specifically, I followed the poster's recommendation, which was to create a GlobalKey and associate it with the Scaffold widget, and use the context from that key when creating the dialog. In my case, I have a globally accessible object which holds the GlobalKey:

MyGlobals myGlobals = MyGlobals();
class MyGlobals {
  GlobalKey _scaffoldKey;
  MyGlobals() {
    _scaffoldKey = GlobalKey();
  }
  GlobalKey get scaffoldKey => _scaffoldKey;
}

In the Scaffold widget constructor call:

Scaffold(
  appBar: ...,
  body: ...,
  drawer: ...,
  key: myGlobals.scaffoldKey,
)

And in the showDialog call:

showDialog<String>(
  barrierDismissible: ...,
  builder: ...,
  context: myGlobals.scaffoldKey.currentContext,
);
Mariellamarielle answered 12/5, 2019 at 22:0 Comment(3)
@ajs.sonawane Do you mean that it doesn't work when you create a dialog from within a dialog, or it doesn't work when you try to use it a second time with the same dialog, or that it doesn't work if you use it for one dialog, close that dialog, and then open a different dialog?Mariellamarielle
nope, calling dialog then popping it and then calling it againParachute
@Parachute It seems to be working for my situation ... perhaps you will need to post a new question. Sorry.Mariellamarielle
S
21

You’re trying to access a context that isn’t probably available. That happens because you’ve assigned your Dialog to a var and afterwards use a different context (the one from your dialog builder).

Either create your dialog directly after your return in the builder or make it a method instead that returns a Dialog and pass it a BuildContext parameter.

Widget myDialog(BuildContext context) => Dialog(/*your dialog here*/);

This is also a more convenient Flutter practice. You should use methods that return widgets instead of assigning it to variables.

Shing answered 10/2, 2019 at 15:13 Comment(2)
You need to provide more code context/info then. At first glance that's what it seems, because when you are popping the Dialog you may be referring to an invalid widget context.Shing
This is not a convenient flutter practice. See https://mcmap.net/q/98153/-what-is-the-difference-between-functions-and-classes-to-create-reusable-widgetsSpriggs
M
21

use this:

Navigator.of(context,rootNavigator: true).pop();

instead of

Navigator.of(context).pop();
Mcmahan answered 19/3, 2021 at 4:38 Comment(3)
Can you elaborate a bit on this? Why / in which cases is the latter preferable?Kraska
For Explaination please visit : #60350241Euell
This will not necessarily help. If your context is outdated, this might still fail, as even with the rootNavigator: true part you are still accessing a BuildContext that is no longer viable. Also: you might discover unwanted navigation behaviour, e.g., when you use tab bars.Radiomicrometer
A
9

This might happen while you are popping from the context and trying to open new content on the context you are popping.

()async{
    Navigator.of(context).pop();
    _alertPopUp(); // shows a dialog
    // might do some work after
}

if alert dialog is created on current context then it throws an error because context doesn't exist anymore

Asclepiadaceous answered 3/1, 2021 at 15:15 Comment(1)
It didn't work for me.Roup
V
5

My problem was that I was using hot reload for pretty long time, I think at some point everything got messed up, doing a normal run of the app fixed the problem.

Venter answered 24/9, 2021 at 0:14 Comment(2)
Seems like this is the answer which worked i dont know if flutter could be notified of this issueBalkin
this is exactly my case. suddenly catch an error when try to navigate, then i restart and everything work normal again.Anadiplosis
T
3

Use this if You are using Stack in AlertDialog Not Closing on Navigator.of(context).pop();

late NavigatorState _navigator;

   @override
  void didChangeDependencies() {

    _navigator = Navigator.of(context);

    super.didChangeDependencies();
}

Use This

 Positioned(right: 10.0,child: GestureDetector(

                  // behavior: HitTestBehavior.translucent,

                  onTap: () {
                    _navigator.pop(context);
                    },
                  child: Align(
                    alignment: Alignment.topRight,
                    child: CircleAvatar(
                      radius: 14.0,
                      backgroundColor: Colors.white,
                      child: Icon(Icons.close, color: black),
                    ),
                  ),
                ),
              ),
Tellurian answered 6/2, 2023 at 11:6 Comment(0)
S
2

removing application from emulator and run below commands

flutter clean
flutter pub get 

works for me

Signory answered 12/5, 2022 at 18:19 Comment(0)
K
2

I had the same bug, but in totally different context. I use Riverpod as a state manager, and I wanted to cancel a stream in StatefulWidget dispose method. It turned out that it caused this bug. What I had to do is to use Riverpod's onDispose API.

ref.onDispose(() {
    batteryStateSubscription.cancel();
});

A full example is shown in the documentation

Kluge answered 29/6, 2023 at 18:46 Comment(0)
G
1

before calling a dialog when a page is just loading, call it by adding SchedulerBinding to it, call it like this

SchedulerBinding.instance?.addPostFrameCallback((_) => showDialog( context: context, barrierDismissible: false, builder: (context) { return dialogBox(context, "Fetching account data", 'Profile page', DialogType.processing, function: () {}, dismissText: "", ); }));

Glenine answered 17/8, 2022 at 8:33 Comment(0)
C
1

Though you got desired answer, just for better clarification for others I put my opinion here.

Reason : It is happend due to context mismatch issue. Your passing context to Navigator.of(context).pop() is not matching with your MainApp BuildContext.

Solution : There has 2 way

  1. U can use Global key
  2. pass actual context to your Navigator

Below link I already mentioned how to solve this by passing actual context

https://mcmap.net/q/182144/-unhandled-exception-looking-up-a-deactivated-widget-39-s-ancestor-is-unsafe-how-to-solve-this

Calash answered 2/9, 2022 at 10:57 Comment(0)
A
1

calling Navigator.pop(context) at the beginning of async function worked for me.

Amniocentesis answered 25/2, 2023 at 11:28 Comment(0)
G
1

First let's understand what the framework is saying:

Point - 1:

Looking up a deactivated widget's ancestor is unsafe. At this point the state of the widget's element tree is no longer stable.

This simply means that the widget(parent of Dialog) is no longer present in the widget tree and it can be confirmed by checking the result of context.mounted property. This can be solved by providing a valid BuildContext to the child just by wrapping the Dialog with a Builder class. You can refer this answer to understand the significance of Builder.

show(BuildContext context){
var dialog = Dialog(
  child: Container(
    margin: EdgeInsets.all(8.0),
    child: Form(
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          TextFormField(
            decoration: InputDecoration(
                labelText: "Insira o número de telefone",
                border: OutlineInputBorder(
                    borderRadius: BorderRadius.all(Radius.circular(2.0)))),
          ),
          Row(
            mainAxisAlignment: MainAxisAlignment.end,
            children: <Widget>[
              FlatButton(
                  onPressed: () {
                    Navigator.of(context).pop();
                  },
                  child: Text("Cancelar")),
              FlatButton(
                  onPressed: () {
                    Navigator.of(context).pop();
                  },
                  child: Text("Aceitar"))
            ],
          )
        ],
      ),
    ),
  ),
);

showDialog(
   context: context,
   // Wrapping the clild widget (dialog) within a Builder class.
   builder: (context) => Builder(
     builder: (context) {
      return dialog;
      },
    ),
  );
 }

Point - 2:

To safely refer to a widget's ancestor in its dispose() method, save a reference to the ancestor by calling inheritFromWidgetOfExactType() in the widget's didChangeDependencies() method.

This simply asks us to save the context(reference to the parent widget) before it gets de-activated. The suggestions to use GlobalKey in the above answers simply does the same. As GlobalKey is unique throughout the application, the context is preserved. However, one can also save the context using state management.

Goodspeed answered 22/7, 2023 at 9:29 Comment(0)
C
1

i get answer with this snippet :

  @override
  void didChangeDependencies() {
    Navigator.of(context);
    super.didChangeDependencies();
  }
Celandine answered 19/9, 2023 at 9:3 Comment(0)
F
0

Try this:

    Future<AlertDialog> myDialog(BuildContext context) {
    return showDialog<AlertDialog>(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          content: Container(
            margin: EdgeInsets.all(8.0),
            child: Form(
              child: Column(
                mainAxisSize: MainAxisSize.min,
                children: <Widget>[
                  TextFormField(
                    decoration: InputDecoration(
                        labelText: "Insira o número de telefone",
                        border: OutlineInputBorder(
                            borderRadius:
                                BorderRadius.all(Radius.circular(2.0)))),
                  ),
                ],
              ),
            ),
          ),
          actions: <Widget>[
            FlatButton(
                onPressed: () {
                  Navigator.of(context).pop();
                },
                child: Text("Cancelar")),
            FlatButton(
                onPressed: () {
                  Navigator.of(context).pop();
                },
                child: Text("Aceitar"))
          ],
        );
      },
    );
  }
Fivefold answered 11/2, 2019 at 8:37 Comment(2)
That's akward, I've tested it myself and worked fineFivefold
Can you post here the complete example, please ?Bonze
A
0

declare dialog and set in initState

  late Dialog dialog;

  @override
  void initState() {
    super.initState();

    dialog = Dialog(
      ...
    );
  }
Aindrea answered 8/2, 2022 at 11:30 Comment(0)
H
0

In my case I was using a provider where I used a context as an argument to a function, the thing was that when I passed that page I did it with pushnamedAndRemove Until then on the next page I was trying to use a function where I required the above context, so the error was mine because it was trying to get a parameter that I destroyed earlier, for that reason it didn't work. So be careful if you are deleting old pages.

Heterogeneity answered 9/12, 2022 at 8:57 Comment(0)
L
0

I encountered the error 'Looking up a deactivated widget's ancestor is unsafe.' while working with GetX. Initially, I utilized the 'GetMaterialApp' widget in the main function to launch the app:

void main() => runApp(
  DevicePreview(
    enabled: true,
    builder: (context) => GetMaterialApp(home: const MyApp()), // Wrap your app
  ),
);

However, after switching to the conventional MaterialApp, the issue was resolved:

void main() => runApp(
  DevicePreview(
    enabled: true,
    builder: (context) => MaterialApp(home: const MyApp()), // Wrap your app
  ),
);
Lagrange answered 23/3, 2024 at 5:52 Comment(0)
G
-1

I simply solved this by wrapping the showDialog with a Builder widget, though for me the error came from a stream builder I simply wrap the stream builder with a builder widget and the remove the notify listeners from the a stream am calling in the stream builder, but in your case wrap the showDialog with a Builder widget and it will use the context from the builder, problem solved

Glenine answered 8/12, 2021 at 21:14 Comment(0)
I
-1

first : declare a FormKey.

 GlobalKey<FormState>myFormKey=GlobalKey<FormState>();

second : add the FormKey to your Form widget.

Form( 

 key:myFormKey,

 child:child

 )
Irresolution answered 4/4, 2022 at 4:5 Comment(1)
your example is not related please explain some clearlyMosra
A
-3

In my case i was calling

setState(() {
   Navigator.pop(context);
});
Avow answered 30/4, 2022 at 8:29 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.