오늘의 에러:
E/flutter (19092): [ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: Looking up a deactivated widget's ancestor is unsafe.
E/flutter (19092): At this point the state of the widget's element tree is no longer stable.
E/flutter (19092): 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.
간단하게 축약해보자면
"비활성된 위젯의 상태가 안전하지 않고, dispose()를 안전하게 참조하기 위해 didChangeDependencies() 메소드에서 dependOnInheritedWidgetOfExactType()를 호출해서 참조값을 저장해주세요"
이다.
뭔 소리인지 모르겠으니 영어로 해석하려 하지 말자
오류의 원인:
이 에러를 분석하기 위해 StatefulWidget의 lifecycle을 살펴볼 필요가 있다.
트리의 맨 아래에 위치한 deactivate()와 dispose()는 우리가 보았던 에러 중 나온 단어와 비슷하다는 것을 알 수 있다.
대충 여기에서 에러가 난 건데 lifecycle 중 화면 파기에 해당하는 부분이다.
한 마디로 StatefulWidget이 제대로(정상적으로) 파기되지 않았음을 의미한다.
화면이 파기되려면 대부분 Navigator를 사용하여 화면을 pushReplacement하거나 pop해야 한다.
하지만 왠만하면 Navigator 자체의 문제는 아니고 화면을 파기하는 도중에 동시에 실행하는 것들의 문제다.
화면을 파기하는 도중에 동시에 실행하는 것들은 대부분 3가지 중 하나의 경우로 발생한다.
1. controller를 사용하는 것들
2. 시간이 조금이라도 걸리는 animation
3. setState 함수 등등..
이것들은 Statefulwidget의 lifecycle과 상관없이 별개로 함수가 실행되기 때문에 만약에 Widget이 파기되고 난 후, 이 Widget에서만 실행되는 함수나 animation이 실행된다면 이러한 오류들이 나타날 수 있다.
따라서 오류의 원인은 Navigator를 이용한 비동기 함수를 사용하여서 이미 위젯이 없는데 그 위젯에 뭔가 하려고 하기 때문에 일어난다.
해결 방법:
이 에러의 해결방법은 2가지다.
1. 그냥 냅둔다?
-> 먼 소리냐 하는 분들이 있겠지만 지금까지 앱 개발하면서 이 오류는 디버깅할 때만 발생했으며 디버깅 상태가 아니라면 왠만하면 문제가 되지 않는다. 따라서 신경 안 써도 상관없다.
2. 화면을 파기하는 도중에 동시에 실행하는 것들의 요소를 Widget이 파기 되기 전에 없앤다.
-> 혹시나 모를 상황때문에 에러를 고치고 싶으면 controller를 사용하는 것들 밖에 dispose() 함수를 씌우거나 if(mounted){setState((){})} 를 하는 등 위젯을 벗어났을 때 오류가 날만한 상황을 아예 없애는 것이다. 이건 개발자의 역량이다.
나같은 경우는 아래와 같이 해결한 경험이 있다.