본문 바로가기

개발

[Flutter] Error Handling Widget - 플러터 에러 핸들링하기

반응형
※ 주의
아직 개발 단계여서 업데이트가 있을 수 있다!

※ 바쁜 현대인을 위해서..
해결방법만 보고싶다면 '어떻게 해결' 검색해서 결론만 보시오

 

# 플러터에서 렌더링 에러시 보여주는 방법

플러터에서는 렌더링 시 에러가 발생하면 빨간 컨테이너가 나타난다. 

많이 보았을 공포의 빨간 화면!

 

아무것도 안뜨고 콘솔 메시지만 나오는것 보다 낫다고 생각한다.

문제는 유저가 사용하게 되는 릴리즈 버전에서는 위 같이 렌더링 시 에러가 발생하면 회색 화면이 나온다는 것이다.

앱을 켰는데 회색 화면만 보게되면... 사용자는 떠나버릴거다. 무서운 빨간 화면 보다는 낫겠지만....

 

# ErrorWidget 을 사용한 에러 핸들링

그래서 플러터에서는 ErrorWidget 클래스를 제공한다. ErrorWidget.builder에 렌더링 에러시 보일 화면을 정의하는 것이다.

https://api.flutter.dev/flutter/widgets/ErrorWidget-class.html#widgets.ErrorWidget.1

 

ErrorWidget class - widgets library - Dart API

A widget that renders an exception's message. This widget is used when a build method fails, to help with determining where the problem lies. Exceptions are also logged to the console, which you can read using flutter logs. The console will also include ad

api.flutter.dev

그러나 이경우는 내 프로젝트에서는 적절하지 않았다.

현재 프로젝트에서 메인이 되는 HomeScreen 에서 N번째 위젯에서 Exception이 발생할 경우 해당 위젯만 ErrorWidget 빌더에 정의한 위젯이 나왔다. 

하지만 원하는 결과는 페이지 구성하는 어떤 위젯에서든 에러가 발생하면 HomeScreen 전체를 에러 페이지로 보여주고 싶었다. (UX디자이너와 의논 결과 전체 에러 페이지로 보이는 것이 낫다고 결론났다.)

그러면 어떤 방식을 사용해야할까? 

 

# 에러 위젯이 아닌 에러 스크린을 보여주고싶어

아이디어를 여러개 시도했지만 어느것도 되지 않았다. 그 때 참고했던 블로그를 공유한다. (혹시 이 방법이 먹히는 분들이 있을 수 있으니까^^)

https://acaroom.net/ko/blog/youngdeok/%ED%94%8C%EB%9F%AC%ED%84%B0%EC%9D%98-%EB%8B%A4%EC%96%91%ED%95%9C-%EC%97%90%EB%9F%AC-%EC%83%81%ED%99%A9-%EB%8B%A4%EB%A3%A8%EA%B8%B0-flutter-error-handling

 

플러터의 다양한 에러 상황 다루기 - Flutter Error Handling

앱을 만들때는 정상적인 시나리오를 벗어난 사용 혹은 상황에 따라 다양한 에러를 만날 경우가 많다. 예를 들면 어떤 목록을 불러와 화면에 리스트에 뿌린다고 했을 때, 제일먼저 인터넷이 연결

acaroom.net

https://medium.com/@parthbhanderi01/complete-guide-to-flutter-error-handling-techniques-and-code-examples-37414dd0992f

 

Complete Guide to Flutter Error Handling: Techniques and Code Examples

Error handling is essential to creating mobile apps since it makes sure that even in the face of unforeseen problems, your Flutter app will…

medium.com

 

그러나 두 블로그 다 내 상황에서는 동작하지 않았다. 무엇보다 하위 위젯인 ErrorWidgetBuilder 에 onError 메소드와  builder 를 전달했다한들 에러 발생시 ErrorHandlerWidget의 빌더가 렌더링 될 여지가 없는데 이게 동작한다는 게 이해되지 않았다. 

혹시 지금 내 프로젝트에선 main 위젯에서 MaterialApp위젯을 순수하게(?) 쓰는게 아니라  MaterialApp.router 네임드생성자에 riverpod Provider로 생성한 goRouter 객체를 넘겨서 라우팅을 하고 있어서 위젯트리가 다르게 생성되나? 그래서 re-render 조건이 달라지는 걸까? 이건 한 번 다른 예제 프로젝트를 만들어서 검증해보아야겠다.

새로운 아이디어가 필요했다.

 

# 어떻게 해결했냐면요.

위에서 밝혔다시피 내 프로젝트는 riverpod과 go_router로 환경 설정을 했다.

라우터 설정은 다음과 같다.

이것이 나의 최고의 아웃풋이었다... 허허..

 

그림은 구리지만.. 어떤 경로에서 접근하든 초기 라우트를 제외하고는 어떤 페이지로 이동하든 DashboardScreen을 거쳐야 했다. DashboardScreen은 Bottom Navigation을 보여줄지 여부, 음악이 재생중인지 Stream을 열어두고 음악 재생관련 UI를 보여줄지 등등을 관리했다.

그렇다면 에러도 여기서 처리하면 되지 않을까 싶었다. 새로운 페이지를 렌더링하다가 에러가 발생하면 감지했다가 에러 페이지로 리렌더링 하면 되것지.. 했던 것.

그래서 DashboardScreen 위젯을 다음과 같이 변경했다.

class _DashboardScreenState extends ConsumerState<DashboardScreen> {
  bool itemDragged = false;
  Offset _offset = Offset(314.w, 387.h);
  bool showErrorPage = false;

  @override
  void initState() {
    super.initState();
    // Set up global error handling
    FlutterError.onError = (details) {
      print('Caught error: ${details.exception}');
      showErrorPage = true;
      WidgetsBinding.instance.addPostFrameCallback((_) => setState(() {}));
    };
  }

  @override
  Widget build(BuildContext context) {
    return showErrorPage
        ? const ErrorScreen()
        : LayoutBuilder(builder: (context, constraints) {
            return Scaffold(   //{이하 정상 상태일 때 렌더링 되어야하는 내용들..}

1. re-render를 시킬 수 있는 조건을 위해 변수 shoErrorPage를 선언했다. 기본값은 false 

2. initState에서 렌더링시 발생하는 모든 에러를 캐치하는 FlutterError.onError 에 콜백메서드를 전달했다. 수행하는 내용은 print로 콘솔 메시지를 남기고 showErrorPage 값을 true로 바꿔준 뒤, 모든 위젯 바인딩이 종료되었을 때 setState로 변경된 showErrorPage에 따른 re-render를 하는 것.

  -> print 부분은 서버에 로그를 전송하든, 로거로 로그를 남기든.. 에러를 트래킹할 수 있는 다양한 방법을 사용하면 된다.

3. build() 에서는 showErrorPage에 따라서 에러페이지를 보여줄지, 정상 상태일 때 렌더링될 페이지를 보여줄지 분기를 나눴다.

에러 스크린은 각자 알아서 원하는 대로 정의하시면 될듯!!

 

# 결과

 

일부러 오류상황을 만들어 테스트 한 결과 제대로 잘 됐다.

네트워크 Exception시에도 위 방법을 활용해 네트워크 오류 페이지로 이동할 수 있게 만들고 싶은데.. 일단 우선순위 높은 다른 일부터 처리하고 해야겠다.

만약 해당 프로젝트처럼 에러페이지가 아닌 다이얼로그로 처리하고 싶은 사람들은 showDialog를 조건에 따라서 호출하면 될 것 같다.

 

 

 

 

 

반응형