Flutter의 비동기 함수에서 BuildContext 쓰기

2023년 8월 9일 수정

예전에 Flutter 프로젝트에서 잘 쓰던 코드가 어느날 "Don't use 'BuildContext's across async gaps."라는 경고를 내기 시작했다. 이 문제의 원인과 해결법을 알아보자.

정확한 문제

문제가 발생한 Dart 코드는 대략 아래와 같은 식이다.

onPressed: () async {
  // ...
  Navigator.pop(context); // <-- Warning
}

어떤 버튼이 눌렸을 때 뭔가를 수행한 후 pop을 시키기 위한 코드인데 비동기 루틴이 포함되어 있어서 async 로 표기한 클로저 구현이다.

그런데 여기서 Navigator.pop을 호출하는 코드 부분에서 아래와 같은 경고가 발생했다.

Don't use 'BuildContext's across async gaps. Try rewriting the code to not reference the 'BuildContext'.

의미를 해석하자면 비동기 코드 블럭에서 BuildContext 를 바로 쓰지 말라는 의미 같다. BuildContext 를 안전하게 참조할 수 있게 작성하라는 컴파일러의 경고로 이해했다.

이 코드를 그대로 놔둬도 일단 에러는 아니라서 실행은 가능한고 딱히 뭔가 오동작 한다는 느낌은 받지 못 했다. 다만 좀 찜찜할 뿐이었다.

이 찜찜한 경고를 해결해 보자.

해결 (Flutter 3.7 미만)

단순하게도 BuildContext 를 써야 하는 곳에서 mounted 라는 프로퍼티를 체크하면 된다고 한다.

따라서 위 코드를 아래와 같이 작성할 수 있다.

if (mounted) {
  Navigator.pop(context);
}

로직만 보면 100% 작동을 보장하는 코드는 아니다. 대신 경고는 사라졌고 개인적으로 테스트 해 본 결과 딱히 문제 없이 완벽하게 작동하는 것처럼 느껴졌다.

해결 (Flutter 3.7 이상)

Flutter 버전을 3.7 혹은 그 이후로 올린 경우라면 위 코드는 에러가 발생한다. mounted 라는 프로퍼티가 BuildContext 로 옮겨갔기 때문이다.

그래서 문제의 코드를 아래와 같이 작성할 수 있다.

if (context.mounted) {
  Navigator.pop(context);
}

이전 버전의 코드와 별 차이는 없는 것 같다.

어쨌든 이렇게 바꾼 뒤 경고도 사라졌고 동작도 잘 하는 것 같다. 동작하지 않았던 경우는 한 번도 본 경험이 없다.

사족

해결은 쉽지만 뭔가 상당히 아쉬운 코드를 작성하도록 만드는 경고 같다.

개인적으로 느김으로 이 경고는 Flutter 팀의 실수에 가까운 디자인 같다. 뭔가 추가로 보충되어서 pop 시의 추가 코딩이 필요 없는 형태로 다시 고쳐지지 않을까 하는 생각까지 들 정도다. 물론 나중에 되어봐야 알겠지만 말이다.