Looking up a deactivated widget's ancestor is unsafe on call from Provider flutter

Viewed 26

This issue is weird in that upon fully restarting the app, it works fine until you navigate to the CreateJoinPage, then navigate back to the homepage and then navigate forward to CreateJoinPage and then try to execute the block of code, the error message will start to pop up. I am creating a listener in CreateJoinPage that listens for input from socket.io:

void createRoomSuccessListener(BuildContext context) {
_socketClient.on('createRoomSuccess', (room2) {
  Provider.of<RoomDataProvider>(context, listen: false)
      .updateRoomData(room);
  Provider.of<RoomDataProvider>(context, listen: false).insertPlayer(room);
  Navigator.push(
    context,
    MaterialPageRoute(
        builder: (contextPage) => const ActivitySelectionPage()),
  );
});

}

and this error is called from either of the two Provider.of lines being part of the code.

This listener is called from my CreateJoinPage(StatelessWidget) as such:

SocketMethods().createRoomSuccessListener(context);

The full error code is:

Error: Looking up a deactivated widget's ancestor is unsafe. At this point, the state of the widget's element tree is no longer stable. To safely refer to a widget's ancestor in its dispose() method, save a reference to the ancestor by calling dependOnInheritedWidgetOfExactType() in the widget's didChangeDependencies() method.

1 Answers

It looks like the problem is that the context gets destroyed in the meantime a socket event arrives. To fix that the listener should be removed if the CreateJoinPage widget is disposed. First, change the CreateJoinPage from StatelessWidget to StatefulWidget to override the disposed method like so:


void removeRoomSuccessListener() {
  _socketClient.off('createRoomSuccess');
}


class CreateJoinPage extends StatefulWidget {

  @override
  State<CreateJoinPage> createState() => _CreateJoinPageState();

  ...
}

class _CreateJoinPageState extends State<CreateJoinPage> {
  @override
  void dispose() {
    SocketMethods().removeRoomSuccessListener(context);
    super.dispose();
  }

  ...
}

And declare the SocketMethods.removeRoomSuccessListener like so:

void removeRoomSuccessListener() {
  _socketClient.off('createRoomSuccess');
}
Related